我一直在构建一个核心数据应用程序来管理一些数据,我被一个表明我的对象不符合KVO的错误所困扰。但是,我没有修改NSManagedObject的默认KVO合规性,现在我还在挠头。
错误影响的应用程序区域是创建一些类别并组织一些将存在于这些类别中的项目。项目可以存在于多个类别中,并且项目和类别视图顺序可以由用户设置。简单的东西。
为了更好地显示这一点,我设置的核心数据模型的关键部分显示如下。我在某种程度上简化了实体的命名和属性:
Category <--------->> CategoryItem <<---------> Item
-------- ------------ --------
name viewPosition name
viewPosition description
此模型连接到界面构建器中的两个ArrayController,一个用于类别,一个用于categoryitems。 categoryitems内容集通过selection.categoryItems绑定设置为类别数组控制器。这些阵列控制器提供两个表视图。类别项表的内容通过arrangeObjects.item.name绑定到CategoryItem A.C控制器。
这一切都完美无缺,而且我拖拽和订购物品和类别到我心中的愿望。
除了一个奇怪的案例。
每当我创建一个只包含一个项目的类别时,请保存,如果我重新打开文档,则会出现以下错误:
无法从<NSTableBinder 0x1627f670>
移除关键路径“item.name”的观察者<NSManagedObject 0x16273380>
,很可能是因为关键字“item”的值已更改,但未发送相应的KVO通知。检查NSManagedObject类的KVO兼容性。
之后,界面似乎崩溃,应用程序变得无法使用。我在网上搜索过,我能发现的是,这表明KVC不合规。但是我在这里使用标准的,几乎没有修改过的Apple课程。
当我仅绑定到CategoryItem的viewPosition时,不会引发错误。即通过arrangeObjects.viewPosition而不是arrangeObjects.item.name。就好像tableitem和item之间的关系在表最初观察的时候没有准备就绪(并且只有当有一个项目时)。
还有其他人遇到过这个吗?谁能想到可能的解决方法?
答案 0 :(得分:2)
原来这是一个错误。这是报告,原因和解决方法。
NSArrayController'自动重新排列内容'为NSManagedObjects引发KVO异常
要点: 当在管理核心数据实体数据的NSArrayController上选中“自动重新排列内容”时,会引发异常“无法删除关键路径”x“的观察者”。
从我的调查看来,似乎在NSArrayController上检查'自动重新排列内容'时,KVO合规性并未完全实现。在大多数情况下,它完美地运作,但我发现有一个特定的案例违反了这种合规性。
很难明确表达,但似乎在尝试访问由NSArrayController管理的实体的关系(即arrangeObjects.person.name)时检查自动重新排列内容。除此之外,它似乎只是在重新打开文档之后以及当该控制器正在管理一组恰好一个项目时...
如果您查看示例项目并按照以下步骤操作可能会更容易......
重现的步骤: 1)打开附加的项目 2)打开MyDocument.xib 3)检查“活动人员”NSArrayController是否选中“自动重新排列内容” 4)建立并去 5)单击左列下方的加号添加一个活动 6)单击右侧栏下方的加号,添加一个活动人员(不多,不少) 7)保存文件 8)重新打开文档
预期结果: 文档重新打开,用户可以通过响应式界面随意添加和删除活动和人员。
实际结果: 一旦右侧列尝试仅显示一个活动人员的活动人员,UI就会出现无法预测的行为。使应用程序无法使用。
注意: 我创建了一个测试项目来找到这个bug,代码和模型应该是非常不言自明的,但是如果有任何问题,请随时与我联系。
通过取消选中Auto Rearrange Content并手动调用NSArrayController上的arrangeObjects,可以解决此问题。
答案 1 :(得分:1)
经过多次头部划伤和脚印,我终于解决了这个问题。哇噢!
这个问题的原因实际上是我埋在我的一个表视图中的NSNumberFormatter的一个实例。我应该更多地关注我从Interface Builder获得的控制台消息。
23/06/2009 15:05:08 ibtool[2324] -[NSConcreteAttributedString initWithString:] called with
nil string argument. This has undefined behavior and will raise an exception in post-
Leopard linked apps. This warning is displayed only once.
这实际上意味着我的NSNumberFormatter没有它的零符号和零符号集(默认配置)。将这两者都设置为零可以消除上述错误,然后就像魔术一样,我再次符合KVO。
我发现这可能是以下帖子引起上述控制台消息: http://www.cocoabuilder.com/archive/message/cocoa/2009/5/28/237646
该消息确实让我担心,但因为它似乎并没有影响我的应用程序并且是由'ibtool'(即不是我的应用程序)生成的,所以我最初选择忽略它。主要是因为我不知道在哪里可以找到提出警告的罪魁祸首。直到我用谷歌搜索控制台消息,我才能解决它。我想在Cocoa调试的世界里我还有很多需要学习的东西!
我仍然觉得奇怪的是它只影响了重新打开的文档,只有一个类别中的一个项目......
答案 2 :(得分:0)
无法从
<NSTableBinder 0x1627f670>
移除关键路径“item.name”的观察者<NSManagedObject 0x16273380>
,很可能是因为关键字“item”的值已更改,但未发送相应的KVO通知。检查NSManagedObject类的KVO兼容性。
这确实是最可能的解释。您在未发布KVO通知的情况下更改了值。
你可能正在做这样的事情:
[item release];
item = [newItem retain];
这是错误的。直接实例变量赋值不会发布KVO通知,因此该语句不会告知其他对象有关更改的信息。
您需要通过访问者。一种方法是显式访问者消息:
[self setItem:newItem];
另一种方式是财产分配:
self.item = newItem;
它们都是等效的,并给出完全相同的结果,其中包括KVO通知。
请注意,两个正确的解决方案都不包含retain
或copy
消息。这是你的setter访问器的工作(无论你是否合成它,让Core Data动态创建它,或者自己编写)。
always-use-accessors规则的主要例外是您应该始终在{{中使用相应的release
和retain
/ copy
消息进行直接的实例变量分配1}}方法和init
方法。否则,您将消息发送到half-inited / -deallocked对象。