独立ManagedObjectContext中的Coredata对象错误与持久性存储中的更改

时间:2013-09-16 12:33:01

标签: iphone cocoa-touch cocoa core-data nsfetchedresultscontroller

我有一个操作对象,它创建了自己的托管对象上下文。当主线程集中在UI方面时,操作对象基本上执行计算以从主线程中取消负载。此操作对象的MOC在应用程序中共享一个公共持久存储。

有时会发生这样的情况:在执行操作时,主线程的MOC会收到后端更改的通知。因此,我尝试合并MOC的更改,其中可能发生模型对象中的一些删除。在极少数情况下,正如我所观察到的,操作对象可能尚未实现,并且它们处于错误状态,同时主线程将更改存储到MOC(以及持久存储)中。我的应用程序崩溃了。

根据标准文本,我有一个专用的MOC用于我的线程,根据我的理解,应该从线程的MOC访问故障数据。它是否有助于从线程的MOC访问故障请求,例如,同一个对象可能已从商店中删除?

请参阅此堆栈跟踪: enter image description here

处理此问题的更好方法是什么?

我从这篇文章中了解到:https://stackoverflow.com/a/5722914/260665线程的托管对象上下文不知道商店下面的更改,并且预期商店中存在故障对象。所以,更好的是:

  1. 使用NSManagedObjectContextDidSaveNotification通知(来自:https://stackoverflow.com/a/5722914/260665

  2. 在尝试使用MOC上的NSManagedObject访问其属性之前,检查商店中是否存在-existingObjectWithID的记录(来自:https://stackoverflow.com/a/14297708/260665

  3. 处理代码中的异常? (最后,来自:https://stackoverflow.com/a/15361906/260665

  4. 我不可能继续使用解决方案1& 2因为它不是NSManagedObject的属性直接访问,我有NSFetchedResultController,其中有应用程序崩溃的排序描述符:

    -(NSMutableArray*)fetchedTaskObjects
    {
        if (nil==fetchedTaskObjects_ && self.taskLocalFetchedResultsController && self.persistantTaskFetchedResultsController)
        {
            NSArray *allNonPersistantTasks = [self.taskLocalFetchedResultsController fetchedObjects];
            NSArray *allPersistantTasks = [self.persistantTaskFetchedResultsController fetchedObjects];
    
            fetchedTaskObjects_ = [[NSMutableArray alloc] init];
            [fetchedTaskObjects_ addObjectsFromArray:allNonPersistantTasks];
            [fetchedTaskObjects_ addObjectsFromArray:allPersistantTasks];
            NSSortDescriptor *tasksSortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"self.mockTaskCounter"
                                                                                  ascending:YES];
            NSSortDescriptor *shortTextSortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"self.shortText"
                                                                                      ascending:YES];
            NSSortDescriptor *headerTextSortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"self.accountAssignmentText"
                                                                                       ascending:YES];
            [fetchedTaskObjects_ sortUsingDescriptors:[NSArray arrayWithObjects:tasksSortDescriptor, shortTextSortDescriptor, headerTextSortDescriptor, nil]];
        }
        return fetchedTaskObjects_;
    }
    

    那么任何以正确的方式找到解决方案的建议?

    修改 我得到的错误(例外):

    CoreData could not fulfill a fault for '0x2b0298a0 <x-coredata://E7E91AFC-5BE6-4996-B28F-92CD115A5D0A/CSTaskRegister/p14746>'
    

    它崩溃了哪条线?

    它在任何一个排序描述符中崩溃,其中faluted Managed对象的内部属性试图通过排序描述符访问以进行排序。由于它是一个线程,我们不确定在商店中何时删除了底层对象。因此,线程崩溃有时也会出现在我的统计计算代码中。

    为什么要结合两个FRC的结果?

    因为,该项目最初开始时针对这两个案例采用了不同的MOC,现在尽管MOC是单一的,但差别仍然存在。但我不认为让离散的FRC具有自己的目的是一个问题。

2 个答案:

答案 0 :(得分:1)

做了足够的研究,避免这种情况发生的唯一方法是通过收听通知来更新集合(问题中提到的第一个解决方案),另一种方法是使用-existingObjectWithID进行双重检查(第二个解决方案) )在访问属性之前。

但在我的情况下,排序描述符在内部访问已删除(来自持久存储)托管对象的属性。让我别无选择,只能处理线程中的异常(第三个解决方案)并忽略该线程的(错误的)结果。

答案 1 :(得分:1)

如果您无法合并或者不想触摸操作MOC - 例如因为它当前正在使用,您需要保证操作数据更新变成序列化

这个想法是,当操作运行时,它假定它当前的数据状态视图是常量,因此必须不能被改变。

您有几个选择来保证这一点:

如果某个操作正在运行,并且您收到了更新请求并希望立即更新包括共享持久存储的数据,则需要先取消该操作并等待该操作已执行完成(随后在操作系统的MOC上不会进行访问)。然后开始更新主MOC中的数据。当包含持久存储的更新完成后,您可以使用新初始化的正确合并的 MOC重新启动操作 - 反映数据的实际状态。

同样,您可以将更新请求推迟到运行操作完成之后。