/ / Impedir que uma variável atribuída fracamente seja desalocada sem criar um ciclo de retenção - toque de cacau, cacau, contagem automática de referências, blocos c de objetivo, centro de notificação

Impede que uma variável fracamente atribuída seja desalocada sem criar um ciclo de retenção - toque de cacau, cacau, contagem automática de ref., Object-c-blocks, nsnotificationcenter

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 niled 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 № 1

Há 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ê.