Estou um pouco confuso sobre o uso de blocos no Objective-C. Atualmente, uso o ARC e tenho muitos bloqueios no meu aplicativo, atualmente sempre se referindo ao self
invés de sua referência fraca. Essa pode ser a causa desses blocos reter self
e impedir que sejam desalocados? A questão é: devo sempre usar uma weak
referência de self
em um bloco?
-(void)handleNewerData:(NSArray *)arr
{
ProcessOperation *operation =
[[ProcessOperation alloc] initWithDataToProcess:arr
completion:^(NSMutableArray *rows) {
dispatch_async(dispatch_get_main_queue(), ^{
[self updateFeed:arr rows:rows];
});
}];
[dataProcessQueue addOperation:operation];
}
ProcessOperation.h
@interface ProcessOperation : NSOperation
{
NSMutableArray *dataArr;
NSMutableArray *rowHeightsArr;
void (^callback)(NSMutableArray *rows);
}
ProcessOperation.m
-(id)initWithDataToProcess:(NSArray *)data completion:(void (^)(NSMutableArray *rows))cb{
if(self =[super init]){
dataArr = [NSMutableArray arrayWithArray:data];
rowHeightsArr = [NSMutableArray new];
callback = cb;
}
return self;
}
- (void)main {
@autoreleasepool {
...
callback(rowHeightsArr);
}
}
ios
iphone
objective-c
automatic-ref-counting
weak-references
the_critic
fonte
fonte
Respostas:
Ajuda a não se concentrar na parte
strong
ouweak
na discussão. Em vez disso, concentre-se na parte do ciclo .Um ciclo de retenção é um loop que ocorre quando o Objeto A retém o Objeto B e o Objeto B retém o Objeto A. Nessa situação, se um dos objetos for liberado:
Portanto, esses dois objetos permanecerão na memória durante toda a vida útil do programa, mesmo que, se tudo estivesse funcionando corretamente, fossem desalocados.
Então, o que nos preocupa é manter ciclos , e não há nada sobre bloqueios que criem esses ciclos. Isso não é um problema, por exemplo:
O bloco retém
self
, masself
não o retém. Se um ou outro é liberado, nenhum ciclo é criado e tudo é desalocado como deveria.Onde você entra em problemas é algo como:
Agora, seu objeto (
self
) tem umastrong
referência explícita ao bloco. E o bloco tem uma forte referência implícitaself
. Isso é um ciclo, e agora nenhum objeto será desalocado adequadamente.Como, em uma situação como essa,
self
por definição já tem umastrong
referência ao bloco, geralmente é mais fácil resolver fazendo uma referência explicitamente fracaself
para o bloco usar:Mas esse não deve ser o padrão padrão que você segue ao lidar com blocos que chamam
self
! Isso deve ser usado apenas para interromper o que seria um ciclo de retenção entre o eu e o bloco. Se você adotasse esse padrão em qualquer lugar, correria o risco de passar um bloco para algo que foi executado depois queself
foi desalocado.fonte
-setCompleteionBlockWithSuccess:failure:
método. Mas, sepaginator
pertencer aViewController
, e esses blocos nãoViewController
forem chamados depois que forem liberados, o uso de uma__weak
referência seria a jogada segura (porqueself
possui o que possui os blocos e, portanto, provavelmente ainda estará presente quando os blocos o chamarem) mesmo que não o mantenham). Mas isso é um monte de "se" s. Realmente depende do que isso deve fazer.MyObject
eSomeOtherObject
ambos são donos do bloco. Mas, como a referência do bloco de voltaMyObject
éweak
, o bloco não é o proprietárioMyObject
. Assim, enquanto o bloco é garantido para existir enquanto querMyObject
ouSomeOtherObject
existir, não há nenhuma garantia de queMyObject
vai existir enquanto o bloco faz.MyObject
pode ser completamente desalocado e, enquantoSomeOtherObject
ainda existir, o bloco ainda estará lá.Você não precisa sempre usar uma referência fraca. Se o seu bloco não for retido, mas executado e descartado, você poderá se capturar com força, pois não criará um ciclo de retenção. Em alguns casos, você deseja que o bloco se mantenha até a conclusão do bloco, para que não seja desalocado prematuramente. Se, no entanto, você capturar o bloco fortemente, e dentro do self de captura, ele criará um ciclo de retenção.
fonte
Concordo totalmente com @jemmons:
Para superar esse problema, é possível definir uma forte referência sobre o
weakSelf
interior do bloco:fonte
->
), onde deseja garantir que realmente obteve uma referência válida e a mantém continuamente em todo o conjunto de operações, por exemplo:if ( strongSelf ) { /* several operations */ }
Como Leo aponta, o código que você adicionou à sua pergunta não sugere um ciclo de referência forte (também conhecido como ciclo de retenção). Um problema relacionado à operação que poderia causar um forte ciclo de referência seria se a operação não estivesse sendo liberada. Embora seu snippet de código sugira que você não definiu sua operação como simultânea, mas, se o tiver, não seria liberada se você nunca publicasse
isFinished
, ou se tivesse dependências circulares ou algo parecido. E se a operação não for liberada, o controlador de exibição também não será liberado. Sugiro adicionar um ponto de interrupção ouNSLog
nodealloc
método da sua operação e confirmar que está sendo chamado.Você disse:
Os problemas do ciclo de retenção (ciclo de referência forte) que ocorrem nos blocos são exatamente como os problemas do ciclo de retenção com os quais você está familiarizado. Um bloco manterá referências fortes a todos os objetos que aparecerem dentro do bloco e não liberará essas referências fortes até que o próprio bloco seja liberado. Portanto, se o bloco referenciar
self
, ou mesmo apenas referenciar uma variável de instância deself
, que manterá forte referência a si mesmo, isso não será resolvido até que o bloco seja liberado (ou nesse caso, até que aNSOperation
subclasse seja liberada).Para obter mais informações, consulte a seção Evitar ciclos de referência fortes ao capturar a si própria do documento Programação com objetivo-C: Trabalhando com blocos .
Se o seu controlador de visualização ainda não estiver sendo liberado, basta identificar onde reside a referência forte não resolvida (supondo que você confirmou que
NSOperation
está sendo desalocado). Um exemplo comum é o uso de uma repetiçãoNSTimer
. Ou algumdelegate
objeto personalizado ou outro que está mantendo umastrong
referência erroneamente . Muitas vezes, você pode usar o Instruments para rastrear onde os objetos estão recebendo suas referências fortes, por exemplo:Ou no Xcode 5:
fonte
Algumas explicações ignoram uma condição sobre o ciclo de retenção. [Se um grupo de objetos estiver conectado por um círculo de relacionamentos fortes, eles se manterão vivos, mesmo que não haja referências fortes fora do grupo.] Para obter mais informações, leia o documento
fonte
É assim que você pode usar o self dentro do bloco:
// chamada do bloco
fonte