2010-07-28 112 views
1

我有一个NSArrayController链接到核心数据对象,设置为自动重新排列内容并由谓词过滤。一切都很好,直到我试图取消关系并分配另一个关系。在这一点上,我的应用程序崩溃,我收到以下错误:KVO问题“无法删除观察者”

Cannot remove an observer for the key path "career.type" from Object, most likely because the value for the key "career" has changed without an appropriate KVO notification being sent. Check the KVO-compliance of the Person class.

从周围窥探,似乎有我的NSArrayController的设置为自动重新编排内容导致此问题。但我试图解决问题,而不必手动重新排列NSArrayController。这里是一个的触发错误的伪代码:

object.career = nil; 
object.field = (Field *)item; 

这里是我的NSArrayController的使用谓词:

(career != NIL && career == %@) || (field != NIL && field == %@) 

凡%@对于这两种情况下是一个CoreData对象。

基本上,它看起来好像NSArrayController有一个为object.career.type设置的观察者,并且当该观察者被自动删除时取消关系会导致问题。所以我想知道如果我以错误的方式去解决这个问题?我是否应该抓取该对象的副本,将其从MOC中删除并重新插入,并设置相应的nil和field设置?

如何正确通知观察者该类型已被取消?请注意,这里提到的所有属性和关系使用符合vanilla KVO的getter/setter。

回答

4

From apples documentation

故障和KVO通知

当核心数据变成对象插入到故障时,键 - 值观察(KVO)更改通知(参见键 - 值观察编程指南)被用于发送该对象的属性。如果您正在观察转换为故障的对象的属性,并随后实现故障,则会收到其值实际上未发生更改的属性的更改通知。

虽然从您的角度来看,这些值在语义上没有变化,但是随着对象的物化,内存中的文字字节也在变化。键值观察机制要求Core Data在从指针比较的角度考虑值发生变化时发出通知。 KVO需要这些通知来跟踪关键路径和相关对象的变化。


所以基本上你会得到一个通知,告诉你即使不是这样也会有变化。所以你必须检查对象是否成为故障。然后删除旧的观察员,并添加一个新的相同的路径...

对我来说,这个工作(示例代码):

- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 
    [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; 

    if ([keyPath isEqualToString:@"pageIndex"]) { 

     // basically remove the observer from the fault object and assign the new 
     if([object isFault]) { 
      [object removeObserver:self forKeyPath:@"pageIndex"]; 
      [the_current_instance_returned_by_core_data addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionOld context:NULL]; 
     } 

     // do whatever you want to do on change... 

    } 
}