NSFetchedResultsController多次调用controllerDidChangeContent委托与陈旧的结果?

时间:2013-03-12 20:02:32

标签: ios core-data nsfetchedresultscontroller

我有一个像这样的coredata模型设置:

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委托上,它被调用右侧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];但行为是一样的。删除的对象仅在第二次调用中删除。

0 个答案:

没有答案