/ / Zapobiegaj cofnięciu alokacji słabo przypisanej zmiennej bez tworzenia cyklu zachowania - kakao-dotyk, kakao, automatyczne liczenie ref, obiektywne-c-bloki, nsnotificationcenter

Zapobieganie dealloc'ed słabo przypisanej zmiennej bez tworzenia cyklu zatrzymania - dotyk kakao, kakao, automatyczne przeliczanie, cel-c-bloki, centrum nsnotyfikacji

Mam dziwny przypadek z ARC, NSNotificationCenter i blokiem. Poniżej znajduje się uproszczony przykład kodu. Z testów wynika, że ​​zarządzanie pamięcią didSaveObserver działa zgodnie z oczekiwaniami, tj. nie tworzy cyklu zachowania i nie jest niled wcześniej removeObserver:.

Jednak moje zrozumienie ARC sprawia, że ​​myślę, że to tylko fuks / dziwactwo, a ARC mógłby nil didSaveObserver przed removeObserver:. Widząc jako didSaveObserver nigdy nie jest zachowywana (jedyne przypisanie dotyczy pliku weak zmienna), to ARC może / (powinno?) natychmiast cofnąć przydział.

Czy poprawnie zrozumiałem zasady ARC? Jeśli tak, to w jaki sposób mogę zapewnić, że didSaveObserver jest zachowywany, aby można go było nie obserwować, ale nie tworzy cyklu utrzymania?

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.
}];
}];

Więcej szczegółów:

Gdyby __weak nie jest dodawany (więc domyślnie __strong) Instruments zgłasza, że ​​istnieje cykl przechowywania.

Odpowiedzi:

0 dla odpowiedzi № 1

W NSNotification.h jest komentarz, który wyjaśnia dlaczego didSaveObserver nie jest zwolniony w tym konkretnym przypadku:

// 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.

Oczywiście to tylko wyjaśnia ten konkretny przypadek.


0 dla odpowiedzi nr 2

Po pierwsze, jak myślisz, dlaczego spowodowałoby to cykl utrzymania? Blok się utrzyma didSaveObserver, tak. By didSaveObserver zachować blok? Nic nie jest udokumentowane na temat zwróconego obiektu obserwatora poza tym, że można go użyć w removeObserver: aby usunąć dodaną obserwację. Możliwe, że w jakiś sposób zachowuje blok lub sam jest blokiem, w którym to przypadku utworzyłoby cykl utrzymania. Jeśli chcesz być bezpieczny, tak, możesz użyć weak odnosić się do obserwatora w bloku.

Widzenie, jak didSaveObserver nigdy nie jest zachowywane (jedynym przypisaniem jest słaba zmienna), wówczas ARC może / (powinien?) natychmiast ją cofnąć.

Chyba że zostanie zachowany przez centrum powiadomień przed powrotem do Ciebie.