gpt4 book ai didi

ios - NSFetchedResultsController无法在子上下文中获取

转载 作者:塔克拉玛干 更新时间:2023-11-02 09:50:16 24 4
gpt4 key购买 nike

我有一个UIManagedDocument,其中包含一些数据,这些数据会使用NSFetchedResultsController在列表中显示。数据会在后台定期更新,并将更改放入UIManagedDocument.managedObjectContext(使用performBlock :)。

当我显示来自文档主要上下文的数据时,所有工作均按预期进行。但是,一旦我在主上下文(child.parentContext = document.managedObjectContext)的子上下文中显示列表,我就看不到任何对象,并且控制台上会显示以下错误:

foo[17895:15203] CoreData: error: (NSFetchedResultsController)
The fetched object at index 5 has an out of order section name 'E.
Objects must be sorted by section name'

这仅在将新对象插入文档联系人后才发生。当我等待足够长的时间以进行自动保存时,列表显示正常。另外,问题仅在于当我在 sectionNameKeyPath上设置了 NSFetchedResultsController且仅具有子上下文时。

这是我设置获取的结果控制器的方式,没什么花哨的,所以在这里我看不到我会做错什么:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Contact"];
fetchRequest.sortDescriptors = [Contact userDefinedSortDescriptors];
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"hidden == nil || hidden == NO"];

NSFetchedResultsController *fetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:_managedObjectContext
sectionNameKeyPath:[Contact userDefinedSectionNameKeyPath]
cacheName:@"ContactList"];
[Contact userDefinedSortDescriptors][Contact userDefinedSectionNameKeyPath]在运行时解析。排序描述符包含sectionNameKeyPath作为第一个条目。 nil或其他有趣的东西都不能。

编辑:澄清了一些模糊的部分。具体来说,我不会在文档托管对象上下文中调用-save:。

编辑2 :我将尝试解释MOC之间的关系。

有三种受管对象上下文在起作用:

1)通过加载文档创建的 UIManagedDocument.managedObjectContext

2)运行一个后台线程,该线程不时更新对象。这是一个以文档MOC为父文档的 private 队列moc:
context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
context.parentContext = repository.managedObjectContext;

[context performBlock:^{ /* updates */ }];
[context performBlock:^{ [context save:NULL]; }];

3)当用户要进行更改时,将创建一个新的MOC作为文档MOC的子代。这是主队列MOC。这是用于执行上面显示的提取的上下文。

后台更新是通过NSOperationQueue完成的,但是所有对后台MOC的访问都被 -performBlock:正确地包围了。所有其他访问均从主线程完成。

编辑3 :在对 NSFetchRequest进行一些设置时,我发现设置 fetchRequest.includesPendingChanges = NO时问题消失了。但这不是一个可行的解决方案,因为在UIManagedDocument将更改保存到后台之前,用户现在看不到任何更新。

最佳答案

这里有几个危险信号给我。首先,这个...

数据会在后台定期更新,并将更改保存到UIManagedDocument.managedObjectContext中(使用performBlock :)。

UIManagedDocuments实现了自动保存,并且唯一应该直接调用save方法的时间是在初始创建时。所有其他“保存”都应通过自动保存界面来完成。基本上,这就是

[document updateChangeCount:UIDocumentChangeDone];

如果您使用UndoManager,这将自动完成。因此,如果您直接输入document.managedContext,您要做的就是调用上述方法来通知托管文档更改已完成,其他所有操作均应自动处理。

其次,我不确定您的意思是什么:

但是,一旦我在子上下文中显示列表,

孩子的上下文是什么?为什么任意上下文会看到任何东西?它是UIManagedDocument主要上下文的子上下文,还是父级,还是其他?

该文档很清楚(对于某些明确的定义),但是不幸的是,它需要阅读UIDocument,UIManagedDocument和所有NSManagedOjectContext的完整文档集。

当我终于把头放在发生的事情上(具有讽刺意味的是,通过阅读有关iCloud的工作方式来阅读)时,与UIManagedDocument相关的所有问题似乎都消失了。

基本上,请遵循以下简单规则:
  • 从不直接在UIManagedDocument中嵌入的任何上下文上调用任何“保存”方法。
  • 当对象是“脏”的并且需要保存时,可以使用撤消管理器注册更改,或者直接调用[doc updateChangeCount:UIDocumentChangeDone]。
  • 如果要使用子上下文,请继续。在这种情况下,您需要做的就是设置parentContext属性,然后在您的子上下文上调用save:。其他一切将自动发生。

  • 编辑
    另一个危险信号是您正在使用不同的上下文运行代码。如果是这种情况,则必须确保从正确的线程运行。 NSManagedObjectContext对象不是线程安全的。因此,必须始终从创建它们的线程中访问它们(如果为NSConfinementConcurrencyType),或者如果是其他两种并发类型之一,则必须使用performBlock进行访问。

    如果要使用多个上下文连续进行插入/获取操作,将需要解决一些问题。主要是,您必须确保所做的更改已传播并计划保存,然后,您的提取操作才可以执行。

    插入完成后,请确保仅使用UIManagedDocument的子上下文调用save。切勿在托管文档上调用save或saveToURL。使用上述方法将其保存。这将确保您正确传播更改。

    提取时,您必须决定是否要让提取一直沿上下文链进行。 NSFetchRequest上有很多选项(例如setShouldRefreshRefetchedObjects)。这些选项将决定获取是否仅使用其自身的上下文,还是进入后备存储,以及其他很多东西。默认值通常是您想要的,但是使用子上下文时,您承担的责任更大。

    另外,如果您有子上下文,则必须确保使用正确的并发类型创建它们,并且仅在适当的线程/队列中使用它们。否则,您将获得不确定的结果。

    编辑

    为了回应您最近提出的问题,请编辑以下语句:

    3)当用户要进行更改时,将创建一个新的MOC作为文档MOC的子代。这是主队列MOC。这是用于执行上面显示的提取的上下文。

    我从未做过,对我来说,是另外一个危险信号。已经有一个主队列MOC-document.managedObjectContext。如果要在主线程中处理文档,请使用该选项。记住,CoreData仍然在线程包含模型上运行,并且实际上每个线程只需要一个MOC。新的API提供了使MOC与队列相关联的方法,并提供了帮助,但是我敢打赌,每个线程有多个MOC会引起问题。通常,我会避免这种情况。

    关于ios - NSFetchedResultsController无法在子上下文中获取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10188319/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com