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 nil
ed 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 № 1W 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.