objective-c - 当实例化对象时,向已释放的对象发送 NSKeyValueNotifyObserver 消息时如何发生 BAD ACCESS

标签 objective-c cocoa exc-bad-access key-value-observing

我们遇到了这个奇怪的问题。 当我们实例化一个对象时,我们还实例化了属于该对象的属性:

-(instancetype)init
{
   self = [super init];
   if (self) {
     [self setDocument];
   }
   return self;
}

-(void)setDocument:
{
   _flatGraphicsArrayController = [[NSArrayController alloc] initWithContent:doc.flattenedObjects];
}

...偶尔会在 _flatGraphicsArrayController 设置时发生 EXC_BAD_ACCESS

调用堆栈:
enter image description here

此崩溃已确定是由于将 NSKeyValueNotifyObserver 消息发送到已释放的对象而引起的,该对象似乎正在观察 flatGraphicsArrayController 的更改

对我来说,这非常令人困惑,因为拥有此属性的对象刚刚被实例化,所以怎么可能有任何东西观察到该属性的更改?

是否有人注册来观察特定的内存地址(如果这就是它的工作原理),然后 flatGraphicsArrayController 以某种方式占用了内存中的该空间,而观察者被释放?

最佳答案

某个对象 (Object1) 作为观察者添加到另一个对象 (Object2)。此后的某个时间,Object1 和 Object2 都被释放,但没有任何操作将 Object1 作为 Object2 的观察者删除。键值观察者的关系保持在任一对象之外(因为当添加 KVO 时,出于二进制兼容性原因,无法将新的实例变量添加到 NSObject 中,因此它必须将其状态存储在边 table )。

KVO 应该在释放 Object1 时提示这一点。检查控制台日志。

无论如何,在稍后的某个时间,您将创建 NSArrayController 的实例。它恰好与Object2占用相同的地址。这意味着它与KVO关于Object1和Object2之间的观察关系的内部信息相匹配。因此,实际上,失效的 Object1 现在正在观察您的阵列 Controller 。当其属性发生更改时,它会向 Object1 发送 KVO 更改通知。当然,Object1 已经不存在了。根据其地址是否已被重用以及该地址是新对象的基地址还是指向其中的某个位置,结果可能是崩溃或无声。

要解决此问题,您需要始终在释放被观察对象或观察对象之前删除 KVO 观察。

关于objective-c - 当实例化对象时,向已释放的对象发送 NSKeyValueNotifyObserver 消息时如何发生 BAD ACCESS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33180279/

相关文章:

c - 程序收到信号 : “EXC_BAD_ACCESS” ?

objective-c - 将键盘快捷键发送到 Mac OS X 窗口

ios - ScrollView 中的移动按钮 - iOS

ios - addChildViewController 给出 NSException 错误?

objective-c - 什么clang-format选项控制方法调用参数的格式?

cocoa - 在 MacBook Pro 上检测类似 iPhone 的多点触控 "tap"

macos - 为什么我的 cocoa 程序在启动期间获得 EXC_BAD_ACCESS?

objective-c - 从 NSImageCell 中获取显示的图像

cocoa - WebKit 尝试播放_任何_ flash 内容时崩溃

c++ - 为什么 mglData 会导致 BAD ACCESS 异常?