8

我有一个这样的核心数据模型设置:

TileList <->> TileListOrder
TileListOrder <<-> Tile

并且创建了一个 NSFetchedResultsController:

NSPredicate* predicate = [NSPredicate predicateWithFormat:@"tile <> nil AND tileList <> nil AND tile.removed == 0 AND  tileList.removed == 0"];
NSSortDescriptor* sortTileListDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"tileList.order" ascending:YES] autorelease];
NSSortDescriptor* sortTileDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"order" ascending:YES] autorelease];

NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setPredicate:predicate];

[fetchRequest setSortDescriptors:sortDescriptors];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"TileListOrder" inManagedObjectContext:coreManagedObjectContext];
[fetchRequest setEntity:entity];

NSFetchedResultsController* fetchedResults = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                                                                 managedObjectContext:coreManagedObjectContext
                                                                                   sectionNameKeyPath:@"tileList.order"
                                                                                            cacheName:nil];

我还在辅助 NSManagedObjectContext 上导入数据并将这些更改合并回来,如下所示:

- (void) localContextDidSave:(NSNotification*) notification {
        dispatch_sync(dispatch_get_main_queue(), ^{
    [coreManagedObjectContext mergeChangesFromContextDidSaveNotification:notification];

        [self didSaveModelToCoreDataPersistentStore];

    });

    [super didEndUpdatingObjectInBackgroundThread];

}

我正在添加和删除 TileListOrders 对象。它从 6 个对象和 3 个部分开始,当我完成时,删除了 6 个原始对象并插入了 6 个新对象。

现在我的问题是在 NSFetchedResultsController 委托上,它在 mergeChangesFromContextDidSaveNotification:notification 之后立即被调用

-(void)controllerDidChangeContent:(NSFetchedResultsController *)controller{

 NSLog(@"controller has %d sections, %d results:",[[controller sections] count], [[controller fetchedObjects] count]);
}

第一次打印 12 个对象和 3 个部分时被称为 TWICE,第二次在 3 个部分中打印 6 个对象。

在检查 fetchedObjects 时,第一次有 6 个插入的对象加上其他 6 个被删除的原始对象。第二次它包含预期的 3 个部分中的 6 个对象。

看着:

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject

   atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type

  newIndexPath:(NSIndexPath *)newIndexPath{
}

第一次调用 controllerDidChangeContent 时,仅处理 NSFetchedResultsChangeInsert 更改,第二次仅处理 NSFetchedResultsChangeDelete 更改。

我希望 controllerDidChangeContent 只有在处理完所有更改后才会被调用。如果这是驱动一个 tableView 那么这意味着 tableview 将动画两次。一次用于插入的项目,另一个用于已删除的项目。问题是,第一次调用 controllerDidChangeContent 时,NSFetchedResultsController 中的对象已被删除,但仍存在于结果数组中,现在它们的属性值无效,因此显示这些项目的 tableView 可能会崩溃。

任何人都知道如何使更改合并,以便在收到 mergeChangesFromContextDidSaveNotification 通知后仅调用一次 controllerDidChangeContent 吗?

-----------更新---------------

更多信息。

我只是在观察 NSManagedObjectContextDidSaveNotification 并且 localContextDidSave 只被调用一次。

NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
[defaultCenter addObserver:self selector:@selector(localContextDidSave:) name:NSManagedObjectContextDidSaveNotification object:managedObjectContext];

这是堆栈跟踪。第一次调用 controllerDidChangeContent 时,仅报告与 INSERTED 对象相关的更改,并且已删除的对象仍然存在于 NSFetchedResultsController 结果中。如您所见,它是由

#0  0x001fb735 in -[HomeViewController controllerDidChangeContent:] 
#1  0x02947f9a in -[NSFetchedResultsController(PrivateMethods) _managedObjectContextDidChange:] ()
#2  0x022d34f9 in __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_0 ()
#3  0x02e1c0c5 in ___CFXNotificationPost_block_invoke_0 ()
#4  0x02d76efa in _CFXNotificationPost ()
#5  0x02207bb2 in -[NSNotificationCenter postNotificationName:object:userInfo:] ()
#6  0x0285a163 in -[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:] ()
#7  0x0286dc71 in -[NSManagedObjectContext _mergeChangesFromDidSaveDictionary:usingObjectIDs:] ()
#8  0x0286ce2e in -[NSManagedObjectContext mergeChangesFromContextDidSaveNotification:] ()
#9  0x00044be2 in __50-[CoreDataUpdateableObject localContextDidSave:]_block_invoke 
#10 0x0306f731 in _dispatch_barrier_sync_f_slow_invoke ()
#11 0x0307e014 in _dispatch_client_callout ()
#12 0x0306e7d5 in _dispatch_main_queue_callback_4CF ()
#13 0x02d68af5 in __CFRunLoopRun ()
#14 0x02d67f44 in CFRunLoopRunSpecific ()
#15 0x02d67e1b in CFRunLoopRunInMode ()
#16 0x038617e3 in GSEventRunModal ()
#17 0x03861668 in GSEventRun ()
#18 0x01756ffc in UIApplicationMain ()
#19 0x000022c6 in main 

第二次调用 controllerDidChangeContent 时,堆栈跟踪是:

#0  0x001fb735 in -[HomeViewController controllerDidChangeContent:] 
#1  0x02947f9a in -[NSFetchedResultsController(PrivateMethods) _managedObjectContextDidChange:] ()
#2  0x022d34f9 in __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_0 ()
#3  0x02e1c0c5 in ___CFXNotificationPost_block_invoke_0 ()
#4  0x02d76efa in _CFXNotificationPost ()
#5  0x02207bb2 in -[NSNotificationCenter postNotificationName:object:userInfo:] ()
#6  0x0285a163 in -[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:] ()
#7  0x028f3d2f in -[NSManagedObjectContext(_NSInternalChangeProcessing) _createAndPostChangeNotification:withDeletions:withUpdates:withRefreshes:] ()
#8  0x02855596 in -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] ()
#9  0x02854869 in -[NSManagedObjectContext processPendingChanges] ()
#10 0x02828e38 in _performRunLoopAction ()
#11 0x02d8aafe in __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ ()
#12 0x02d8aa3d in __CFRunLoopDoObservers ()
#13 0x02d687c2 in __CFRunLoopRun ()
#14 0x02d67f44 in CFRunLoopRunSpecific ()
#15 0x02d67e1b in CFRunLoopRunInMode ()
#16 0x038617e3 in GSEventRunModal ()
#17 0x03861668 in GSEventRun ()
#18 0x01756ffc in UIApplicationMain ()
#19 0x000022c6 in main

这一次它是由:[NSManagedObjectContext processPendingChanges] () 这第二次 NSFetchedResultsController 结果实际上具有所需的状态:删除的对象被删除,插入的对象存在。

我的问题是第一个 mergeChanges 应该触发具有合并更改的 controllerWillChangeContent,因此结果应该处于一致状态。

从发布的原始代码中,我确实添加了 [coreManagedObjectContext processPendingChanges]; [coreManagedObjectContext mergeChangesFromContextDidSaveNotification:notification] 之后;因为没有这个,第二次调用只会在下一次运行循环时触发。

我也试过 [coreManagedObjectContext setPropagatesDeletesAtEndOfEvent:NO]; 但行为是一样的。已删除的对象仅在第二次调用中被删除。

4

0 回答 0