Objective c 在实例化对象时,向解除分配的对象发送NSKeyValueNotifyObserver消息时,如何发生错误访问
我们遇到了这个奇怪的问题。 当我们实例化一个对象时,我们还实例化了一个属于该对象的属性:Objective c 在实例化对象时,向解除分配的对象发送NSKeyValueNotifyObserver消息时,如何发生错误访问,objective-c,cocoa,exc-bad-access,key-value-observing,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] initWithCont
-(instancetype)init
{
self = [super init];
if (self) {
[self setDocument];
}
return self;
}
-(void)setDocument:
{
_flatGraphicsArrayController = [[NSArrayController alloc] initWithContent:doc.flattenedObjects];
}
…在设置\u平面图形阵列控制器时,偶尔会发生EXC\u BAD\u访问
调用堆栈:
已确定此崩溃是由向解除分配的对象发送NSKeyValueNotifyObserver
消息引起的,该对象似乎正在观察对FlatGraphicsRayController的更改
对我来说,这是非常混乱的,因为拥有这个属性的对象刚刚被实例化,所以怎么可能有任何东西在观察属性的变化呢
是否有人注册以观察特定的内存地址(如果它是这样工作的),然后flatGraphicsArrayController
在释放观察者时以某种方式占用了内存中的空间?某个对象(Object1)被添加为另一个对象(Object2)的观察者。在那之后的某个时候,Object1和Object2都被解除分配,但没有任何东西将Object1作为Object2的观察者删除。键值观察者的关系保持在两个对象之外(因为当添加KVO时,出于二进制兼容性的原因,不能向NSObject
添加新的实例变量,因此它必须将其状态存储在一个副表中)
KVO应该在解除分配Object1时对此进行投诉。检查控制台日志
无论如何,在以后的某个时间,您将创建NSArrayController
的实例。它恰好与Object2占用相同的地址。这意味着它匹配KVO关于Object1和Object2之间观察关系的内部信息。因此,实际上,失效的Object1现在正在观察您的阵列控制器。当其属性发生更改时,它会向Object1发送KVO更改通知。当然,Object1已经不存在了。根据其地址是否被重用,以及该地址是否为新对象的基址或其中的某个点,结果可能是崩溃或静默
要解决此问题,您需要在解除分配被观测对象或观测对象之前始终删除KVO观测值。谢谢您的回答;这就是问题的症结所在。当不同类型的对象占用旧对象2的内存空间时会发生什么情况?不客气。我不知道你在问什么。在本例中,很可能“不同类型的对象占用旧对象2的内存空间”。这就是问题所在。所以KVO系统不关心正在观察的对象——如果它被释放并替换为不同类型的对象,而新对象发生了变化,它仍然会发送通知?e、 有东西在观察人和物体。此人被释放。一个Dog对象替换它在内存中的位置。Dog对象更改,原始观察者是否收到通知?或者,只有当Person对象被另一个人替换时,原始观察者才会收到通知吗?类型没有多大关系,没有。KVO确实会切换观察对象的类,以便与它们的setter和其他变化的访问器挂钩,但这不是对象生成更改通知的唯一方式。当使用KVC对它们进行变异时,或者如果它们显式地调用-will/didChange…
方法等,它们就会这样做。您关注的是错误的事情。分析KVO在一个显然已经崩溃的场景中会做什么是毫无意义的。修复在解除分配任一对象之前移除观察器的失败,以及KVO在发生故障时的行为变得无关紧要。明白。事实上,我们找到了观测结果未能被移除的地方。这是因为在试图移除观察者的过程中,接收器为nil
。但是现在我不明白为什么接收器变成了nil
。如果你感兴趣的话,我还发布了另一个问题:再次感谢你在这里的时间:)谢谢