当控制器被释放时,键值观察者仍然在其中注册

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

***由于未捕获的exception’NSInternalInconsistencyException’而终止应用程序,原因是:’MyController2类的实例0x167e5980已取消分配,而键值观察者仍在其中注册。

Current observation info:  ( <NSKeyValueObservance 0x16719fb0: Observer: 0x167e5980, Key path: dataContainer.report, Options:  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 *)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和dealloc中删除观察者: –

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

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

根据我的经验,在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 *)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]; } } } 

在dealloc中删除Observer:

这里打电话删除一次

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

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

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

使用KeyPath观察者的Swift 4 KVO适用于iOS 11(可能还有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和iOS 11发行说明