iOS5 CoreData在父母和子女MOC上同时触发故障导致崩溃

时间:2012-02-21 08:19:19

标签: core-data nested

说我有 4 MOC (托管对象上下文),如下所示:

rootMOC (后台保存) - > fetchMOC (后台抓取) - > mainMOC (与UI相关)

rootMOC - > networkMOC (网络相关)

'A->B' means A is a parent of B.

所以工作流程是这样的:

  • 在networkMOC中创建对象,[确定]
  • 保存到rootMOC,[确定]
  • 将objectID传递给fetchMOC和mainMOC [确定]
  • 调用[moc objectWithID :objectID] [确定]
  • fetchMOC &中
  • [moc refreshObject :对象mergeChanges: YES ] mainMOC 进行更改[确定]

  • 稍后我访问导致故障的对象属性同时在fetchMOC和mainMOC中触发 [轰隆,崩溃!]

我确定的事情:

  • 使用 NSPrivateQueueConcurrencyType NSMainQueueConcurrencyType 正确设置所有MOC。
  • 所有与MOC相关的API调用都是包装在performBlock 中,甚至只是访问托管对象的属性(可能会导致错误)。

以下是线程4中的代码崩溃( fetchMOC

comparator = [^NSComparisonResult(id obj1, id obj2) {
                ArticleInfo* info1 = obj1;
                ArticleInfo* info2 = obj2;
                if (info2.timeStamp > info1.timeStamp) { //[Thread4 fetchMOC:Crash]
                    return NSOrderedAscending;
                } 
                else if (info2.timeStamp == info1.timeStamp) {
                    return NSOrderedSame;
                }
                else {
                    return NSOrderedDescending;
                }
            } copy];

同时在mainMOC中发生了什么:

[self.fetchMOC performBlock:^{
                    [self.fetchMOC refreshObject:self.currentUserFetchMOC mergeChanges:YES];
                    for (Stream* stream in self.currentUserFetchMOC.streams) {
                        [self.fetchMOC refreshObject:stream mergeChanges:YES];
                    }
                    [self.mainMOC performBlock:^{
                        LogMessage(@"MainMOC", 0, @"%@", @"Refresh steams Begin");
                        [self.mainMOC refreshObject:self.currentUserMainMOC mergeChanges:YES];
                        for (Stream* stream in self.currentUserMainMOC.streams) {
                            [self.mainMOC refreshObject:stream mergeChanges:YES];
                            if ([stream.uri isEqualToString:self.currentUserMainMOC.currentStreamURI]) {//Thread 1, here
                                self.currentStreamMainMOC = stream;
                            }
                        }
                        LogMessage(@"MainMOC", 0, @"%@", @"Refresh steams End");
                    }];
                }];

修改

为何失败

在检查我的代码的每一行后,我找出原因。 我通过用existingObjectWithID替换objectWithID来检查,​​以确保对象已经存在于fetchMOC和mainMOC中。结果是一个惊喜,nowObjectWithID返回nil。所以我认为原因是[networkMOC save]没有保存所有同步,并且我不应该在保存返回后立即调用objectWithID。

解决方法

我只是在调用[fetchMOC mergeChangesFromContextDidSaveNotification]之后立即将所有对象合并代码移动到 NSManagedObjectContextDidSaveNotification处理程序,这次existingObjectWithID返回有效对象并且不会再次崩溃。

仍然喜欢

会话303 - iOS上核心数据的新功能告诉我,通过使用嵌套的MOC,我可以在兄弟MOC之间共享未保存的更改,这就是我试图实现的(我失败了)。据我所知,没有示例代码/博客/视频显示我在调用[sourceMOC save]之后要做什么,其中Apple人员只是通过访问托管对象的属性来“拉动”更改。通过访问属性显然无法正常工作! 使用mergeChangesFromContextDidSaveNotification时,它只是简单地太慢了。 我在开发论坛中创建了一个帖子,到目前为止都没有得到答案。

https://devforums.apple.com/message/624382#624382

1 个答案:

答案 0 :(得分:0)

召,

维持MOC之间的一致性可能很棘手。 MOC易于创建和销毁。持久性存储及其协调器旨在保持一致性。行缓存非常快。因此,我建议您根据需要创建和销毁MOC。我怀疑当你开始为每个后台操作使用新的MOC时,你的问题就会消失。 (在我的应用程序中,确实如此。)

安德鲁