当取消分配控制器时,键值观察者仍然在其中注册

时间:2016-06-05 09:36:57

标签: ios objective-c memory key-value-observing dealloc

我在代码中添加了一个观察者,然后在dealloc和viewWillDisappear中将其删除但是我仍然收到错误说明

  

***由于未捕获的异常终止应用程序' NSInternalInconsistencyException',原因:'实例0x167e5980 of   类值MyController2在键值观察者被释放时被释放   仍在注册。

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

我创建了一个控制器MyController,并从中派生出一个新的控制器MyController2。现在我在MyController2中添加了KVO。

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

然后在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];
        }
    }
}

然后我试图在viewWillDisappear中移除观察者并释放两者: -

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

我查看丢失的帖子,所有人都说你需要删除观察者。我试图从他们两个中删除观察者,但我仍然遇到了问题。

2 个答案:

答案 0 :(得分:8)

根据我的经验,在Ios中添加和删除观察者的最佳方式。

在ViewDidLoad中添加观察者: -

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

观察观察者我们必须这样做: -

  

不要删除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];
        }
    }
}

删除Oball中的观察者:

  

在此处调用删除

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

答案 1 :(得分:2)

你应该有一个布尔标志,你应该在添加观察者时将其设置为true,并在删除时将其设置为false。仅当此标志为false时才添加观察者。 在删除观察者之前,还要在viewWillDisappear中添加check。还要添加日志

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