当控制器被释放时,键值观察者仍然在其中注册
我在代码中添加了一个观察者,然后在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发行说明
- 没有'|' 候选产生预期的上下文结果types“NSTextStorageEditActions”
- 在“〜/ Library / Developer / Xcode / iOS DeviceSupport”中缺lessiOS符号
- 除了调用indexPath之外,还可以通过其他方法以编程方式selecttableView中的行
- 快速的构建时间重新分析和优化
- 从ALAssetRepresentation中为CGImageRef设置最大大小
- 使用委托从button传递信息突出显示单元格
- 在锁定iPhone时,想要我的YTPlayerView中的下一个和上一个按钮
- 删除应用程序后,获取推送通知的设备令牌
- iPhone应用程序本地化通过为不同市场发布单独的应用