KVO und ARC, wie man den Server entfernt

87

Wie entferne ich einen Beobachter aus einem Objekt unter ARC ? Fügen wir einfach den Beobachter hinzu und vergessen, ihn zu entfernen? Wenn wir den Speicher nicht mehr manuell verwalten, wo treten wir dann von der Beobachtung zurück?

Zum Beispiel auf einem View Controller:

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

Zuvor habe ich removeObserver:die deallocMethode des View Controllers aufgerufen .

betrunkener Bass
quelle
4
Beachten Sie, dass es für KVO .frame eine sehr schlechte Idee ist. Wie von Apple-Ingenieuren zu StackOverflow geschrieben, ist die Frame-Eigenschaft von UIKit nicht KVO-kompatibel. Wenn es funktioniert, ist es nur Zufall.
Steipete
2
Sollte Ihr keyPath nicht @"frame"eher sein als @"self.frame"?
Besi

Antworten:

126

Sie können weiterhin -deallocunter ARC implementieren. Dies scheint der geeignete Ort zu sein, um die Beobachtung von Schlüsselwerten zu entfernen. Sie rufen mit [super dealloc]dieser Methode einfach nicht mehr auf.

Wenn Sie -releasevorher überschrieben haben, haben Sie die Dinge falsch gemacht.

Brad Larson
quelle
1
Bist du dir da sicher? Ich zitiere aus clang.llvm.org/docs/… , Abschnitt 7.1.2. Dealloc: "Begründung: Obwohl ARC Instanzvariablen automatisch zerstört, gibt es immer noch legitime Gründe, eine Dealloc-Methode zu schreiben, z. B. die Freigabe nicht aufbewahrbarer Ressourcen. Das Nichtaufrufen von [Super Dealloc] in einer solchen Methode ist fast immer ein Fehler."
Elise van Looij
@ElisevanLooij Ja das stimmt. Wenn Sie aus dieser Klasse stammen, ist es offensichtlich, dass Sie anrufen müssen [super dealloc]. Wer sollte das noch für Sie tun?
Björn Landmesser
@ ElisevanLooij Ups, nun, sollte vorher überprüft haben. Es ist nicht gestattet, [super dealloc]eine Dealloc-Methode aufzurufen. Keine Ahnung, wie das dann funktionieren würde, wenn die erwähnte Klasse untergeordnet wird. Vielleicht ist es nur ratsam, finalizestattdessen zu verwenden (wo Sie anrufen [super finalize])
Björn Landmesser
17
@ElisevanLooij - Der Punkt, den sie dort ansprechen wollten, betrifft den Fall der manuellen Speicherverwaltung. Da das Nichtaufrufen von [super dealloc]last in dieser Methode bei der manuellen Speicherverwaltung so gut wie immer ein Fehler ist, behandelt der Compiler dies jetzt für Sie, weshalb Sie nicht -deallocmehr direkt aufrufen können. Die einzigen Dinge, die Sie in eine -deallocMethode unter ARC einfügen, sind nicht objektbezogene Ressourcen, die Sie freigeben müssen, oder Bereinigungsaufgaben wie das Entfernen von Beobachtern. Der Wortlaut, den sie verwenden, ist etwas matschig, aber das haben sie gemeint.
Brad Larson
7
@ BjörnMilcke - Wie ich zu Elises Antwort kommentiere, -finalizewird dies unter Garbage Collection verwendet, wo -dealloces nie aufgerufen wird, aber es ist durchaus akzeptabel, diesen Code -deallocunter ARC zu platzieren. [super dealloc]wird automatisch für Sie aufgerufen, weshalb es ein Fehler ist, es unter ARC aufzurufen.
Brad Larson
1

Ich mache es mit diesem Code

- (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
}
}    
user3461902
quelle
2
Worum geht es bei der Ausnahmebehandlung dealloc? Es ist zu spät, etwas dagegen zu unternehmen.
Abizern
Was bringt es, Beobachter für eine Instanzvariable in Dealloc zu entfernen? Dieses uAvatarImage wird in Kürze zusammen mit allen Beobachtern, die es für seine Schlüsselpfade abonniert hat, freigegeben.
Shoumikhin
1
@shoumikhin Ich benutze ARC und musste den Beobachter in der Dealloc-Methode entfernen. Ich habe die gleiche Frage wie Sie. Wenn ich jedoch mehrere Instanzen der Klasse ausführte, wurde schließlich der Fehler exc_bad_address angezeigt. Dadurch wurde das Problem behoben. Die Antwort von hier stackoverflow.com/questions/32490808/… hat mir auch geholfen, das Problem zu entdecken.
Mac10688
-2

An anderer Stelle beim Stapelüberlauf empfiehlt Chris Hanson, zu diesem Zweck die Finalize-Methode zu verwenden und eine separate Invalidierungsmethode zu implementieren, damit Eigentümer den Objekten mitteilen können, dass sie fertig sind. In der Vergangenheit habe ich festgestellt, dass Hansons Lösungen gut durchdacht sind, also werde ich damit weitermachen.

Elise van Looij
quelle
13
Beachten Sie, dass er sich dort auf die Speicherbereinigung bezog, nicht auf ARC (seine Antwort wurde 2008 geschrieben). Unter Garbage Collection -deallocwird nie aufgerufen. In ARC ist es. Es ist durchaus akzeptabel, KVO-Beobachter zu entfernen -dealloc, wie Chris Lattner (der weiß, wovon er spricht) in Apples Entwicklerforen hier angibt
Brad Larson
3
Vielen Dank, Brad, für all diese Arbeit. Nein zum Abschluss, ja zum Dealloc, aber ohne [Super Dealloc]. Einfach, wenn Sie es einmal wissen. Hey, @drunknbass, akzeptiere die Antwort dieses Mannes!
Elise van Looij