我有一个NSFetchedResultsController,它使用谓词来获取对象:
isTrash == NO
在大多数情况下,此操作都按预期进行,但是当对象未完成处理时,提取的结果 Controller 将不会提取未处理的对象。

怎么了

最佳答案

发生这种情况的原因是mergeChangesFromContextDidSaveNotification:如何处理更新的对象。 NSManagedObjectContext保留上下文中正在使用的对象的记录,这些对象称为注册对象(NSManagedObjectContext具有访问和有条件地获取注册对象的方法)。 mergeChangesFromContextDidSaveNotification:仅处理在上下文中注册的对象的更新。这对NSFetchedResultsControllers产生了影响,说明了问题的原因。

播放方法如下:

  • 使用与所有对象都不匹配的谓词设置FRC(从而防止将与谓词不匹配的对象注册到FRC上下文中)。
  • 第二个上下文更改了一个对象,这意味着它现在与FRC谓词匹配。第二个上下文被保存。
  • FRC上下文处理NSManagedObjectContextDidSaveNotification,但仅更新其已注册对象,因此不会更新现在与FRC谓词匹配的对象。
  • 保存时FRC不会执行其他提取,因此不知道应包含更新的对象。

  • 解决方法

    解决方案是在合并通知时获取所有更新的对象。这是一个示例合并方法:
    -(void)mergeChanges:(NSNotification *)notification {
        dispatch_async(dispatch_get_main_queue, ^{
            NSManagedObjectContext *savedContext = [notification object];
            NSManagedObjectContext *mainContext = self.managedObjectContext;
            BOOL isSelfSave = (savedContext == mainContext);
            BOOL isSamePersistentStore = (savedContext.persistentStoreCoordinator == mainContext.persistentStoreCoordinator);
    
            if (isSelfSave || !isSamePersistentStore) {
                return;
            }
    
            [mainContext mergeChangesFromContextDidSaveNotification:notification];
    
            //BUG FIX: When the notification is merged it only updates objects which are already registered in the context.
            //If the predicate for a NSFetchedResultsController matches an updated object but the object is not registered
            //in the FRC's context then the FRC will fail to include the updated object. The fix is to force all updated
            //objects to be refreshed in the context thus making them available to the FRC.
            //Note that we have to be very careful about which methods we call on the managed objects in the notifications userInfo.
            for (NSManagedObject *unsafeManagedObject in notification.userInfo[NSUpdatedObjectsKey]) {
                //Force the refresh of updated objects which may not have been registered in this context.
                NSManagedObject *manangedObject = [mainContext existingObjectWithID:unsafeManagedObject.objectID error:NULL];
                if (manangedObject != nil) {
                    [mainContext refreshObject:manangedObject mergeChanges:YES];
                }
            }
        });
    }
    

    09-28 07:08