我有一个像这样的coredata模型设置:
TileList <->> TileListOrder
TileListOrder <<-> Tile
使用:
创建的NSFetchedResultsControllerNSPredicate* 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委托上,它被调用右侧aftter 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];因为没有这个,第二次调用只会在下一次运行的runloop中触发。
我也试过[coreManagedObjectContext setPropagatesDeletesAtEndOfEvent:NO];但行为是一样的。删除的对象仅在第二次调用中删除。