2015-07-29 3 views
5

ich einen einfachen Viewcontroller, die KVO-kompatibel ist und hat folgend drin:iOS KVO - Kann nicht einen Beobachter entfernen

- (void) viewDidAppear:(BOOL)animated 
    { 
     [super viewDidAppear:animated]; 



     [self addObserver:self forKeyPath:@"importStuff" options:0 context:NULL]; 
     [self addObserver:self forKeyPath:@"importStuffFailed" options:0 context:NULL]; 
     } 

    - (void) viewWillDisappear:(BOOL)animated 
    { 
     [super viewWillDisappear:animated]; 

     [self removeObserver:self forKeyPath:@"importStuff"]; 
     [self removeObserver:self forKeyPath:@"importStuffFailed"]; 
     } 

das Problem im ist mit, dass manchmal Benutzer die folgenden Fehler berichten:

Cannot remove an observer <MyViewController 0x145d0c8d0> for the key path "importStuff" from <MyViewController 0x1741b2280> because it is not registered as an observer. 

Der Aufruf von addObserver wird nirgendwo sonst im Code aufgerufen. Ist es etwas über die Lebenszyklen, die ich vermisse? ist nicht viewDidAppear garantiert einmal aufgerufen werden (so sollte es die Schlüssel richtig registrieren?)

+2

Dies ist kein sicherer Weg, KVO zu handhaben. Wenn Ihre App durch einen Anruf unterbrochen wird, wird viewWillDisappear nicht aufgerufen, aber viewDidAppear kann erneut aufgerufen werden, wenn die App neu gestartet wird. Es gibt viele andere weniger als ideale Möglichkeiten. Sie sollten in Betracht ziehen, zuverlässigere Methoden zum Hinzufügen und Entfernen von Beobachtern zu verwenden (viewDidLoad, dealloc, usw.) – gurooj

+0

danke für das Wissen. Was passiert, wenn ich addObserver zweimal anrufe? Muss ich dann auch zweimal den removeObserver entfernen? Auch dieser Artikel sagt, dass ViewDidAppear nur einmal aufgerufen wird: http://stackoverflow.com/questions/11534396/when-is-viewdidappear-called – j2emanue

+0

beantwortet Ihre Frage nicht, aber Sie können sich vor dem Fehler mit '@try {[self removeObserver : self forKeyPath: @ "yourKeyPath"];} @catch (NSException * __unused exception) {} ' – vib

Antwort

4

Es gibt keine Garantie, dass ein viewDidAppear mit einem viewWillDisappear jedes Mal abgestimmt wird. Dies bedeutet, dass Ihre KVO-Registrierung/Nicht-Registrierung möglicherweise unausgewogen und nicht-deterministisch ist. Sie sollten die KVO-Registrierung/-Abmeldung in garantierten Paarungen wie viewDidLoad und dealloc durchführen.

7

Apple Docs sagen, es gibt eine Möglichkeit, Beobachter hinzuzufügen, wenn die Ansicht nur sichtbar ist. Gemäß Abbildung 1 - Gültige Statusübergänge können Sie das Paar viewWillAppear/viewWillDisppear zum Hinzufügen und Entfernen von Beobachtern verwenden. Zur gleichen Zeit können Sie init/dealloc Paar verwenden, aber nicht viewDidLoad/dealloc - Ansicht kann nicht geladen werden, aber Controller freigegeben.

sollte Ihr Code sein:

- (void)viewWillAppear:(BOOL)animated 
{ 
    [super viewWillAppear:animated]; 

    [self addObserver:self forKeyPath:@"importStuff" options:0 context:NULL]; 
    [self addObserver:self forKeyPath:@"importStuffFailed" options:0 context:NULL]; 
} 

- (void)viewWillDisappear:(BOOL)animated 
{ 
    [super viewWillDisappear:animated]; 

    [self removeObserver:self forKeyPath:@"importStuff"]; 
    [self removeObserver:self forKeyPath:@"importStuffFailed"]; 
}