KVO e ARC come rimuovereObserver


87

Come rimuovi un osservatore da un oggetto sotto ARC ? Aggiungiamo semplicemente l'osservatore e dimentichiamo di rimuoverlo? Se non gestiamo più la memoria manualmente dove ci rassegniamo dall'osservare?

Ad esempio, su un controller di visualizzazione:

[self.view addObserver:self
            forKeyPath:@"self.frame"
               options:NSKeyValueObservingOptionNew 
               context:nil];

In precedenza, removeObserver:chiamavo il deallocmetodo del controller di visualizzazione .


4
Nota che è una pessima idea per KVO .frame. Come scritto altrove dagli ingegneri Apple su StackOverflow, la proprietà frame di UIKit non è conforme a KVO. Quando funziona, è solo per puro caso.
steipete

2
Il tuo keyPath non dovrebbe essere @"frame"invece di @"self.frame"?
Besi

Risposte:


126

È ancora possibile implementare -deallocin ARC, che sembra essere il luogo appropriato per rimuovere l'osservazione dei valori chiave. Semplicemente non chiami più [super dealloc]dall'interno di questo metodo.

Se -releaseprima avevi la precedenza, stavi facendo le cose nel modo sbagliato.


1
Sei sicuro di questo? Cito da clang.llvm.org/docs/… , sezione 7.1.2. dealloc: "Razionale: anche se ARC distrugge automaticamente le variabili di istanza, ci sono ancora ragioni legittime per scrivere un metodo dealloc, come liberare risorse non conservabili. Non riuscire a chiamare [super dealloc] in un tale metodo è quasi sempre un bug."
Elise van Looij

@ElisevanLooij Sì, è vero. Se derivi da questa classe, sembra ovvio che devi chiamare [super dealloc]. Chi altro dovrebbe farlo per te.
Björn Landmesser

@ElisevanLooij Oops, beh, avrei dovuto controllare prima. Non è consentito chiamare [super dealloc]un metodo dealloc. Non ho idea di come funzionerebbe allora quando si sottoclasse la classe menzionata. Forse è solo consigliabile utilizzare finalizeinvece (dove chiami [super finalize])
Björn Landmesser

17
@ElisevanLooij - Il punto che stavano cercando di fare è riguardo al caso di gestione manuale della memoria. Poiché non chiamare l' [super dealloc]ultimo in quel metodo è praticamente sempre un bug nella gestione manuale della memoria, il compilatore lo gestisce per te ora, motivo per cui non puoi più chiamare -deallocdirettamente. Le uniche cose che metti in un -deallocmetodo sotto ARC sono tutte le risorse non oggetto di cui hai bisogno per liberare o attività di pulizia come la rimozione di osservatori. La formulazione che usano è un po 'confusa, ma questo è ciò che intendevano.
Brad Larson

7
@ BjörnMilcke - Come ho commentato la risposta di Elise, -finalizeviene utilizzato per questo in garbage collection, dove -deallocnon viene mai chiamato, ma è perfettamente accettabile inserire questo codice in -deallocARC. [super dealloc]viene chiamato automaticamente, motivo per cui è un errore chiamarlo sotto ARC.
Brad Larson

1

Lo faccio con questo codice

- (void)dealloc
{
@try{
    [self.uAvatarImage removeObserver:self forKeyPath:@"image" context:nil];
} @catch(id anException) {
    //do nothing, obviously it wasn't attached because an exception was thrown
}
}    

2
Qual è lo scopo della gestione delle eccezioni dealloc? È troppo tardi per fare qualcosa al riguardo.
Abizern

Qual è il punto di rimuovere gli osservatori su una variabile di istanza in dealloc? Questa uAvatarImage sarà presto rilasciata insieme a tutti gli osservatori che ha sottoscritto nei suoi percorsi chiave.
shoumikhin

1
@shoumikhin Sto usando ARC e ho dovuto rimuovere l'osservatore nel metodo dealloc. Ho la stessa domanda che hai tu. Tuttavia, quando ho eseguito più istanze della classe alla fine ho ricevuto l'errore exc_bad_address. In questo modo è stato risolto il problema. Inoltre, la risposta da qui stackoverflow.com/questions/32490808/… mi ha aiutato a scoprire il problema.
mac10688

-2

Altrove sullo stack overflow, Chris Hanson consiglia di utilizzare il metodo finalize per questo scopo e di implementare un metodo invalidate separato in modo che i proprietari possano dire agli oggetti che hanno finito. In passato ho trovato le soluzioni di Hanson ben ponderate, quindi ci andrò.


13
Nota che si riferiva alla raccolta dei rifiuti lì, non ad ARC (la sua risposta è stata scritta nel 2008). In Garbage Collection, -deallocnon viene mai chiamato. In ARC, lo è. È perfettamente accettabile rimuovere gli osservatori KVO -dealloc, come Chris Lattner (chissà di cosa sta parlando) indica nei forum degli sviluppatori Apple qui: devforums.apple.com/message/475850
Brad Larson

3
Grazie Brad, per aver fatto tutto questo lavoro. No alla finalizzazione, sì alla deallocazione ma senza [super dealloc]. Semplice davvero, una volta che lo sai. Ehi, @drunknbass, accetta la risposta di quell'uomo!
Elise van Looij
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.