2016-06-05 23 views
1

ich einen Beobachter im Code hinzugefügt und entfernt sie dann in dealloc und viewWillDisappear aber noch bin ich eine Fehlermeldung bekommenSchlüsselwert Beobachter waren noch bei ihm registriert, wenn die Steuerung freigegeben wird

Angabe *** App beenden wegen für die nicht abgefangene Ausnahme 'NSInternalInconsistencyException', Grund: 'Eine Instanz 0x167e5980 der Klasse MyController2 wurde freigegeben, während Schlüsselwertbeobachter noch registriert waren.

Current observation info: <NSKeyValueObservationInfo 0x16719f90> (
<NSKeyValueObservance 0x16719fb0: Observer: 0x167e5980, Key path: dataContainer.report, Options: <New: YES, Old: YES, Prior: NO> Context: 0x0, Property: 0x1677df30> 
)' 

habe ich einen Controller, MyController und einen neuen Controller MyController2 daraus ziehen. Jetzt habe ich KVO in MyController2 hinzugefügt.

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    [self addObserver:self forKeyPath:@"dataContainer.report" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil]; 
} 

Dann in observeValueForKeyPath: -

- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context { 

    id oldC = [change objectForKey:NSKeyValueChangeOldKey]; 
    id newC = [change objectForKey:NSKeyValueChangeNewKey]; 

    if([keyPath isEqualToString:@"dataContainer.report"]) { 
     if (oldC != newC) { 
      //Remove Observer 

      [self removeObserver:self forKeyPath:@"dataContainer.report" context:nil]; 
      [self updateDataContainer]; 
      [self reportView]; 
     } 
    } 
} 

Dann habe ich versucht, Beobachter in viewWillDisappear zu entfernen und dealloc beides: -

- (void)dealloc { 
    @try{ 
     [self removeObserver:self forKeyPath:@"dataContainer.report" context:nil]; 
    }@catch(id anException){ 
    } 
} 

-(void) viewWillDisappear:(BOOL)animated{ 
    @try{ 
     [self removeObserver:self forKeyPath:@"dataContainer.report" context:nil]; 
    }@catch(id anException){ 
    } 
    [super viewWillDisappear:animated]; 
} 

ich verloren Pfosten sah, alle von ihnen sagen eine Sache, die Sie Beobachter entfernen müssen. Ich habe versucht, Beobachter von beiden zu entfernen, aber ich bekomme immer noch das Problem.

+0

Der Fehler zeigt, dass Sie Für den Schlüsselpfad 'dataContainer.inspectionReport' wurde ein Observer hinzugefügt, der Code zeigt jedoch den Schlüsselpfad als 'dataContainer' an .report'. –

+0

@MidhunMP Tut mir leid, eigentlich habe ich diesen Teil vom Code geändert und vergisst, den Fehler zu ändern. Jetzt habe ich es geändert.Bitte lassen Sie mich wissen, wenn Sie etwas finden, warum ich den Fehler –

+0

bekomme Ich würde vorschlagen, überall zu loggen, die Sie Beobachter hinzufügen und entfernen, und ich wette, Sie werden finden, dass sie nicht ausgeglichen sind. – Rob

Antwort

3

Aus meiner Erfahrung besten Weg, melden Sie sich zum Hinzufügen und Entfernen Beobachter in Ios.

hinzufügen Beobachter in ViewDidLoad: -

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    [self addObserver:self forKeyPath:@"dataContainer.report" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil]; 
} 

Um den Beobachter zu beobachten wir haben, dies zu tun: -

Sie in observeValueForKeyPath nicht entfernen Beobachter

- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context { 

    id oldC = [change objectForKey:NSKeyValueChangeOldKey]; 
    id newC = [change objectForKey:NSKeyValueChangeNewKey]; 

    if([keyPath isEqualToString:@"dataContainer.report"]) { 
     if (oldC != newC) { 
      [self updateDataContainer]; 
      [self reportView]; 
     } 
    } 
} 

Entfernen Beobachter in Dealloc:

Anruf zu entfernen, sobald hier

- (void)dealloc { 
    @try{ 
     [self removeObserver:self forKeyPath:@"dataContainer.report" context:nil]; 
    }@catch(id anException){ 
    } 
} 
2

Sie sollten ein boolesches Flag haben, das Sie als wahr festlegen sollten, wenn ein Beobachter hinzugefügt wird, und beim Entfernen auf false setzen. Fügen Sie nur Beobachter hinzu, wenn dieses Flag falsch ist. Fügen Sie außerdem check in viewWillDisappear hinzu, bevor Sie den Beobachter entfernen. Fügen Sie auch

if (self.isMovingFromParentViewController || self.isBeingDismissed) { 
     if (isReportKVOAdded) { 
      [self removeObserver:self forKeyPath:@"dataContainer.report" context:nil]; 
     } 
    } 
+0

Sie müssen Beobachter so viele Zeit entfernen, wie Sie hinzugefügt haben, kann dies durch Verwendung Fahnen verhindert werden – Atif

+0

ja ein Bool für Add Having und entfernen Observer gute Idee. Für mich geht das. – cmp

0

Swift 4 KVO KeyPath Beobachter mit Arbeit auf iOS 11 (und wahrscheinlich macOS 10,13)

@objcMembers class Foo: NSObject { 
     dynamic var string = "bar" 
    } 

    var observation: NSKeyValueObservation! 

    func TestKVO() { 

     var foo = Foo() 

     // kvo in 2 lines of code 
     observation = foo.observe(\.string) { observed, change in 
      print(observed.string) 
     } 

     foo.string = "yo" // prints "yo" 
     foo = Foo() // works on iOS 11, crashes MacOS 10.12, not tested on MacOS 10.13, yet 
     foo.string = "oy" // does not print 
    } 

macOS 10.13 and iOS 11 Release Notes

+1

zu beachten, ich diese Technik verwende aber haben ein paar Probleme mit ihm macOS 10.13.2/XCode 9.2 hatte. Ich habe versucht, auf mein unbekanntes Selbst zuzugreifen, aber es wurde bereits freigegeben. Hinzufügen deinit {Beobachtung .invalidate()?} Meine Klasse, um die Abstürze gestoppt - so wurde etwas nicht gereinigt werden, wie es sollte. – Giles