在实例化对象时,如何在向已释放的对象

时间:2015-10-16 22:08:27

标签: 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];
}

...偶尔会在EXC_BAD_ACCESS

的设置下发生_flatGraphicsArrayController

调用堆栈:
enter image description here

此崩溃已确定是由于将NSKeyValueNotifyObserver消息发送到已解除分配的对象,该对象似乎正在观察对flatGraphicsArrayController的更改

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

是否有人注册观察特定的内存地址(如果它是如何工作的),然后flatGraphicsArrayController以某种方式占用内存中的那个空间,而观察者被解除分配?

1 个答案:

答案 0 :(得分:2)

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

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

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

要解决此问题,您需要在取消分配观察对象或观察对象之前始终删除KVO观察值。