Tenho um caso estranho envolvendo ARC, NSNotificationCenter e um bloco. A seguir está um exemplo simplificado do código. Dos testes, parece que o gerenciamento de memória de didSaveObserver
está funcionando como desejado, ou seja, não está criando um ciclo de retenção e não está sendo nil
ed antes removeObserver:
.
No entanto, meu entendimento do ARC me faz pensar que isso é apenas um acaso / peculiaridade e o ARC nil
didSaveObserver
antes removeObserver:
. Vendo como didSaveObserver
nunca é retido (a única atribuição é para um weak
variável), o ARC poderia / (deveria?) desalocá-lo instantaneamente.
Eu entendi as regras ARC corretamente? Se sim, como posso garantir que o didSaveObserver
é retido para que não seja observado, mas não crie um ciclo de retenção?
self.willSaveObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextWillSaveNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
id preSaveState = ...; //Store some interesting state about a Core Data object (the details aren"t significant to this question).
__weak __block id didSaveObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
//Unobserve the did save block. This is the tricky bit! didSaveObserver must be __weak to avoid a retain cycle, but doing so also means that the block may be dealloced before it can be unobsered.
[[NSNotificationCenter defaultCenter] removeObserver:didSaveObserver];
id postSaveState = ...;
//Perform work that uses pre & post save states.
}];
}];
Mais detalhes:
E se __weak
não é adicionado (então o padrão é __strong
) Instruments relata que há um ciclo de retenção.
Respostas:
0 para resposta № 1Há um comentário em NSNotification.h que explica por que didSaveObserver
não é desalocado neste caso particular:
// The return value is retained by the system, and should be held onto by the caller in
// order to remove the observer with removeObserver: later, to stop observation.
Claro, isso só explica este caso específico.
0 para resposta № 2
Primeiro, por que você acha que isso criaria um ciclo de retenção? O bloco iria reter didSaveObserver
, sim. Seria didSaveObserver
retém o bloco? Nada está documentado sobre o objeto observador retornado, a não ser que ele possa ser usado em removeObserver:
para remover a observação adicionada. É possível que ele de alguma forma retenha o bloco ou seja o próprio bloco, caso em que criaria um ciclo de retenção. Se você quiser estar seguro, sim, você pode usar weak
para se referir ao observador no bloco.
Ver como didSaveObserver nunca é retido (a única atribuição é para uma variável fraca), então ARC poderia / (deveria?) desalocá-la instantaneamente.
A menos que seja retido pelo centro de notificação antes de retornar para você.