Имам един странен случай, включващ ARC, NSNotificationCenter и блок. По-долу е опростен пример за кода. От тестването изглежда, че управлението на паметта на didSaveObserver
се изпълнява по желание, т.е. не създава задържащ цикъл и не е nil
преди това removeObserver:
.
Въпреки това, моето разбиране за ARC ме кара да мисля, че това е само един fluke / quirk и ARC може nil
didSaveObserver
преди removeObserver:
, Виждайки като didSaveObserver
никога не се задържа (единствената задача е да weak
променлива), тогава ARC може / / трябва? / да го разсее незабавно.
Разбрах правилно правилата на ARC? Ако е така, тогава как да се уверя, че didSaveObserver
се запазва, така че да не може да бъде наблюдавана, но да не се създаде задържащ цикъл?
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.
}];
}];
Повече информация:
ако __weak
не се добавя (така че по подразбиране е __strong
) Инструментите съобщават, че има резервен цикъл.
Отговори:
0 за отговор № 1Има коментар в NSNotification.h, който обяснява защо didSaveObserver
не се дезалтира в този конкретен случай:
// 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.
Разбира се, това обяснява само този конкретен случай.
0 за отговор № 2
Първо, защо мислите, че ще създаде задържащ цикъл? Блокът ще запази didSaveObserver
, да. Би се didSaveObserver
запази блок? Нищо не е документирано за възстановения обект на наблюдателя, различен от този, в който може да се използва removeObserver:
за да премахнете добавяното наблюдение. Възможно е той някак си да задържи блока или да е самият блок, в който случай ще създаде задържащ цикъл. Ако искате да сте в безопасност, да, можете да използвате weak
да се позове на наблюдателя в блока.
Виждайки, че didSaveObserver никога не се запазва (единствената задача е да слаба променлива), тогава ARC би могъл / (трябва?) незабавно да го раздели.
Ако не бъде задържан от центъра за уведомяване, преди да се върнете при вас.