key value observers were still registered with it when controller is deallocated

心不动则不痛 提交于 2020-01-01 06:32:24

问题


I added an observer in the code and then removed it in dealloc and viewWillDisappear but still i am getting an error stating

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'An instance 0x167e5980 of class MyController2 was deallocated while key value observers were still registered with it.

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

I created a controller, MyController and derive a new controller MyController2 from it. Now i added KVO in MyController2.

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

Then 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];
        }
    }
}

Then i tried to remove observer in viewWillDisappear and dealloc both :-

- (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];
}

I looked at lost of posts , all of them say one thing you need to remove observer. I tried to remove observer from both of them but still i am getting the issue.


回答1:


From my experience best way to add and remove observer in Ios.

Add observer in ViewDidLoad:-

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

To observe the observer we have to do this:-

Don't remove observer 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) {
            [self updateDataContainer];
            [self reportView];
        }
    }
}

Remove Observer In dealloc :

call remove once here

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



回答2:


You should have a boolean flag which you should set as true when observer is added and set it false on removing. Add observer only when this flag is false. Also add check in viewWillDisappear before removing observer. Also add log

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



回答3:


Swift 4 KVO using KeyPath observers work on iOS 11 (and probably 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



来源:https://stackoverflow.com/questions/37640432/key-value-observers-were-still-registered-with-it-when-controller-is-deallocated

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!