ary*_*axt 0 objective-c key-value-observing
如何找出对象何时被释放?我正在监听kvo更改,但是在保留计数变为0之前对象被取消分配,并且我收到以下警告:
MyViewController类的实例0x16562be0已取消分配,而键值观察者仍在其中注册.观察信息被泄露,甚至可能被错误地附加到其他物体上.在NSKVODeallocateBreak上设置断点以在调试器中停止.这是目前的观察信息:
基本上我要做的是检测模型何时被解雇.我不能使用Delegate,因为呈现的viewControllers是动态的,我的mainViewController除了它们是UIViewController的子类之外不了解它们.
[anotherViewController addObserver:self forKeyPath:@"retainCount" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionOld | NSKeyValueObservingOptionPrior context:nil];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
// Here check for the changes and see of the new value is 0 or not
}
Run Code Online (Sandbox Code Playgroud)
我也试着监听viewController的superView被改为nil
[anotherViewController.view addObserver:self forKeyPath:@"superView" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionOld | NSKeyValueObservingOptionPrior context:nil];
Run Code Online (Sandbox Code Playgroud)
您只能对对象支持的键执行键值观察.你想在这里做什么根本不可能 - 一个对象的观察者都应该在它到达时消失dealloc.您需要构建应用程序,以便在需要时保留此对象,或者在对象消失之前主动告知感兴趣的各方.
看一个物体retainCount只是一个好主意.只要它有用,它只对调试很有用 - 即使这样,也有更好,更可靠的工具.结果retainCount只是误导,并没有像大多数人期望的那样发挥作用.注意它为0是徒劳的练习,因为保留计数为0时不存在任何对象 - 当释放保留计数为1的对象时,它将被释放,然后您不再被允许发送消息.(实际上,框架实际上无法表示0保留计数,因为它是一个无法访问的状态.)
截至 2017 年末(iOS 11、macOS 10.13),当对象被释放时,它会自动取消注册任何剩余的观察者。来自当年基金会的发行说明:
\n\n\n放宽键值观察注销要求
\n在 10.13 之前,如果在自动通知对象的 -dealloc 完成运行后仍注册任何观察者,KVO 将引发异常。此外,如果所有观察者都被删除,但在释放期间从另一个线程中删除了一些观察者,则仍会正确地抛出异常。\n10.13 中放宽了此要求,但需满足两个条件:
\n\n
\n- 该对象必须使用 KVO 自动通知,而不是手动\n调用 -will 和 -didChangeValueForKey:(即它不应该从 +automaticallyNotizesObserversForKey 返回 NO\n:)
\n- 该对象不得\n覆盖内部 KVO 状态的(私有)访问器
\n如果所有这些都是 true,则 -dealloc\n返回后任何剩余的观察者都将被 KVO 清理;这也比重复调用 -removeObserver 方法更高效。
\n
截至 2020 年底(iOS 14、macOS 10.16),当对象在释放期间仍有观察者时, KVO 会更加小心:
\n\n\n键值观察
\niOS 和 iPadOS 14 beta 5 中的新功能
\n\n
\n- \n
键值观察删除工具现在采用确定性\n簿记方法。原本会产生难以诊断\n崩溃的情况,尤其是那些 KVO 发出信号访问分配的观察者指针或与不正确\n对象关联的观察者时出现问题的情况,\n现在会产生异常,以精确指出哪个观察对象\n需要错过调用
\nremoveObserver(_:),以及哪个观察者\n 。当 KVO 可以检测到问题时,此\n异常之前被抛出为 \xe2\x80\x98best尽力\xe2\x80\x99;removeObserver(_:)新的确定性簿记允许在所有需要的情况下\n抛出它。改进的确定性还允许改进 Swift API 处理。\n
\nNSKeyValueObservation由 Swift\nNSObject.observe(_:changeHandler:)方法生成的 实例\n利用与此簿记的集成,因此它们现在在释放观察到的对象时\n自动失效,无论该对象\n如何实现它的 KVO 行为。这适用于\nmacOS 11 Big Sur beta 中此 API 的所有使用情况,包括使用以前\n版本的 SDK 构建的进程,并消除了\n有时需要使用旧版 API 时\n的某些类型的崩溃。(65051563)
这里有一些问题。
\n一个问题是你问错了问题。你本想问 \xe2\x80\x9c 在目标被释放之前,如何在正确的时间取消注册我的观察者?\xe2\x80\x9d 相反,你提到了 ,retainCount这往往会激起人们责备你使用retainCount而不是帮助你做你想做的事,那就是在正确的时间取消你的观察者的注册。
另一个问题是您的视图控制器不拥有其模型(这意味着它没有对该模型的强引用)。通常您希望视图控制器拥有其模型,以防止出现此类问题。当视图控制器存在时,它需要一个模型来操作,因此它应该拥有该模型。当视图控制器被释放时,它应该停止观察其模型并释放它。(如果您使用 ARC,它将在 结束时自动释放模型dealloc)。viewWillDisappear:如果您的视图控制器反复打开和关闭屏幕,您也可以选择在您的方法中取消注册。
请注意,一个对象可以同时被多个其他对象所拥有。如果您有多个视图控制器在同一模型上运行,那么它们都应该拥有该模型,这意味着它们都应该对该模型具有强引用。
\n第三个问题是您(可能)直接使用 KVO。内置的 KVO API 用起来不太舒服。看一眼MAKVONotificationCenter。当观察者或目标被释放时,这个 KVO 包装器会自动取消注册观察者。
| 归档时间: |
|
| 查看次数: |
2696 次 |
| 最近记录: |