In Cocoa devo rimuovere un oggetto dalla ricezione delle notifiche KVO durante la deallocazione?
Domanda
Quando ho registrato un oggetto pippo per ricevere notifiche KVO da un altro oggetto sbarra (usando addObserver:...), se poi dealloco pippo devo inviare un removeObserver:forKeyPath:
messaggio a sbarra in -dealloc?
Soluzione
Devi usare -removeObserver: forKeyPath:
per rimuovere l'osservatore prima che - [NSObject dealloc]
venga eseguito, quindi sì, facendolo nel -dealloc Il metodo
della tua classe funzionerebbe.
Meglio di così, però, sarebbe avere un punto deterministico in cui qualunque cosa possieda l'oggetto che sta facendo l'osservazione potrebbe dire che è stato fatto e (eventualmente) sarà deallocato. In questo modo, puoi interrompere immediatamente l'osservazione quando la cosa che fa l'osservazione non è più necessaria, indipendentemente da quando è effettivamente deallocata.
Questo è importante da tenere a mente perché la durata degli oggetti in Cocoa non è così deterministica come alcune persone sembrano pensare che lo sia. I vari framework Mac OS X stessi invieranno i tuoi oggetti -retain
e -autorelease
, estendendo la loro durata oltre ciò che altrimenti potresti pensare che sarebbe .
Inoltre, quando si passa alla garbage collection di Objective-C, si troverà che -finalize
verrà eseguito in tempi molto diversi - e in contesti molto diversi - rispetto a -dealloc
. Per prima cosa, la finalizzazione avviene su un thread diverso, quindi in realtà non puoi inviare in sicurezza -removeObserver: forKeyPath:
a un altro oggetto in un -finalize
metodo.
Gestisci la memoria (e altre risorse scarse) in -dealloc
e -finalize
e usa un metodo -invalidate
separato per avere un proprietario dice a un oggetto che hai finito con esso in un punto deterministico; fare cose come rimuovere le osservazioni KVO lì. L'intento del tuo codice sarà più chiaro e avrai meno bug sottili di cui occuparti.
Altri suggerimenti
Un po 'di informazioni extra che ho acquisito da un'esperienza dolorosa: sebbene NSNotificationCenter utilizzi i riferimenti deboli a zero durante l'esecuzione in Garbage Collection, KVO no. Pertanto, puoi evitare di non rimuovere un osservatore NSNotificationCenter quando usi GC (quando usi la conservazione / rilascio, devi comunque rimuovere il tuo osservatore), ma devi comunque rimuovere i tuoi osservatori KVO, come descrive Chris.
Sicuramente d'accordo con Chris sulla gestione di "attenersi alla memoria (e altre risorse scarse) in -dealloc e -finalize ... " commento. Molte volte vedrò persone che provano a invalidare gli oggetti NSTimer nelle loro funzioni dealloc. Il problema è che NSTimer mantiene i suoi obiettivi. Quindi, se il target di quel NSTimer è self, dealloc non verrà mai chiamato provocando perdite di memoria potenzialmente cattive.
Invalida in -invalidate
ed esegui un'altra pulizia della memoria nel tuo dealloc
e finalize.