解 回答很容易但是:它只需要放置[self.tableView beginUpdates];和[self.tableView endUpdates];在正确的地方。 nsfetchcontroller不同意置于didChange内:)
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView beginUpdates];
}
我有一个类,它在主要上下文之外的其他moc中进行更改。 更改完成后,将删除2个对象:
2011-12-21 11:05:06.599 snow[3200:20c1b] CLIENT CONTROLLER:
destination will removed with country:Afghanistan specific:Kabul
2011-12-21 11:05:06.712 snow[3200:20c1b] CLIENT CONTROLLER:
destination will removed with country:Afghanistan specific:Mobile -
AWCC
这导致触发NSFetchedResultsChangeDelete:
2011-12-21 11:05:08.804 snow[3200:1bb03] DESTINATIONS LIST: DELETE : <NSIndexPath 0xb1f8f50> 2 indexes [0, 0]
然而,奇怪的问题正在发生。 Tableview开始获取numberOfRows,然后:
2011-12-21 11:05:08.805 snow[3200:1bb03] Number of rows in section:0 for country:Afghanistan/Mobile - CDMA = 0
2011-12-21 11:05:08.805 snow[3200:1bb03] Number of rows in section:1 for country:Afghanistan/Herat = 0
2011-12-21 11:05:08.805 snow[3200:1bb03] Number of rows in section:2 for country:Afghanistan/Kandahar = 0
2011-12-21 11:05:08.805 snow[3200:1bb03] Number of rows in section:3 for country:Bahrain/Mobile - WiMax = 0
2011-12-21 11:05:08.805 snow[3200:1bb03] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1912.3/UITableView.m:1030
2011-12-21 11:05:21.005 snow[3200:1bb03] CoreData: error: Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. Invalid update: invalid number of sections. The number of sections contained in the table view after the update (4) must be equal to the number of sections contained in the table view before the update (6), plus or minus the number of sections inserted or deleted (0 inserted, 1 deleted). with userInfo (null)
2011-12-21 11:05:21.005 snow[3200:1bb03] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of sections. The number of sections contained in the table view after the update (4) must be equal to the number of sections contained in the table view before the update (6), plus or minus the number of sections inserted or deleted (0 inserted, 1 deleted).'
这是当前的部分数量
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSInteger count = [[[self fetchedResultsController] fetchedObjects] count];
return count;
}
看起来nsfetchresultcontroller启动删除阶段,忘记按照删除步骤的对象执行操作。 Count已经是4个部分,但是获取请求开始只删除一行。
对于本地删除,在self.managedobjectcontext中,一切都可以正常使用相同的代码。 这是fetch控制器委托:
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
[self.tableView beginUpdates];
switch(type) {
case NSFetchedResultsChangeInsert:
{
NSLog(@"DESTINATIONS LIST:INSERT to indexpath :%@",newIndexPath);
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:newIndexPath.row] withRowAnimation:UITableViewRowAnimationTop];
break;
}
case NSFetchedResultsChangeDelete:
{
NSLog(@"DESTINATIONS LIST: DELETE : %@",indexPath);
@synchronized (self) {
if ([self.sections containsIndex:indexPath.row]) [self.sections removeIndex:indexPath.row];
}
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.row] withRowAnimation:UITableViewRowAnimationTop];
break;
}
case NSFetchedResultsChangeUpdate:
{
NSLog(@"DESTINATIONS LIST:UPDATE :%@",indexPath);
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:indexPath.row] withRowAnimation:UITableViewRowAnimationNone];
break;
}
case NSFetchedResultsChangeMove:
{
NSLog(@"DESTINATIONS LIST:CHANGE MOVE from :%@ to %@ ",indexPath,newIndexPath);
BOOL isOpened = NO;
@synchronized (self) {
isOpened = [self.sections containsIndex:indexPath.row];
}
if (isOpened) {
NSLog(@"DESTINATIONS LIST:OPENED CHANGE MOVE from :%@ to %@ ",indexPath,newIndexPath);
[sections removeIndex:indexPath.row];
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.row] withRowAnimation:UITableViewRowAnimationTop];
[sections addIndex:newIndexPath.row];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:newIndexPath.row]] withRowAnimation:UITableViewRowAnimationTop];
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:newIndexPath.row] withRowAnimation:UITableViewRowAnimationTop];
} else {
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.row] withRowAnimation:UITableViewRowAnimationTop];
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:newIndexPath.row] withRowAnimation:UITableViewRowAnimationTop];
}
default:
break;
}
}
[self.tableView endUpdates];
}
self.sections = [[NSMutableIndexSet alloc] init];
同步从不同的线程传递,当然moc是同步所有保存:
moc = [[NSManagedObjectContext alloc] init];
[moc setUndoManager:nil];
[moc setMergePolicy:NSOverwriteMergePolicy];
//[moc setMergePolicy:NSRollbackMergePolicy];
[moc setPersistentStoreCoordinator:coordinator];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(importerDidSave:) name:NSManagedObjectContextDidSaveNotification object:self.moc];
- (void)importerDidSave:(NSNotification *)saveNotification {
//NSLog(@"MERGE in client controller");
if ([NSThread isMainThread]) {
[self.mainMoc mergeChangesFromContextDidSaveNotification:saveNotification];
// [self performSelectorOnMainThread:@selector(finalSave:) withObject:self.moc waitUntilDone:YES];
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:NO] forKey:@"isCurrentUpdateProcessing"];
} else {
[self performSelectorOnMainThread:@selector(importerDidSave:) withObject:saveNotification waitUntilDone:YES];
}
}
有些更新
如果删除只有一个对象,它被删除(传递NSFetchedResultsChangeDelete,触发NSFetchedResultsChangeMove:
2011-12-21 14:04:09.821 snow[5818:1bb03] DESTINATIONS LIST: DELETE : <NSIndexPath 0x933cb50> 2 indexes [0, 0]
2011-12-21 14:04:09.821 snow[5818:1bb03] Number of rows in section:0 for country:Afghanistan/Proper = 0
2011-12-21 14:04:09.821 snow[5818:1bb03] Number of rows in section:1 for country:Bahrain/Mobile - WiMax = 0
2011-12-21 14:04:09.822 snow[5818:1bb03] DESTINATIONS LIST:CHANGE MOVE from :<NSIndexPath 0x933bcb0> 2 indexes [0, 2] to <NSIndexPath 0x936ec10> 2 indexes [0, 1]
2011-12-21 14:04:09.823 snow[5818:1bb03] Number of rows in section:0 for country:Afghanistan/Proper = 0
2011-12-21 14:04:09.823 snow[5818:1bb03] Number of rows in section:1 for country:Bahrain/Mobile - WiMax = 0
获取结果控制器工作更奇怪:
在
[self.tableView endUpdates];
想着10-15秒,后来又做了相同的代码EXC_BAD_ACCESS。
这是消息跟踪:
#0 0x0222109b in objc_msgSend ()
#1 0x00000850 in <????> ()
#2 0x00b580e3 in -[_UITableViewUpdateSupport initWithTableView:updateItems:oldRowData:newRowData:oldRowRange:newRowRange:context:] ()
#3 0x00971e3a in -[UITableView(_UITableViewPrivate) _endCellAnimationsWithContext:] ()
#4 0x0097d211 in -[UITableView endUpdatesWithContext:] ()
#5 0x0097d23f in -[UITableView endUpdates] ()
#6 0x0002b277 in -[DestinationsListPushListTableViewController controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:] at /Users/alex/Desktop/snow/snow iphone/DestinationsListPushListTableViewController.m:1096
#7 0x01978121 in -[NSFetchedResultsController(PrivateMethods) _managedObjectContextDidChange:] ()
#8 0x015b3a39 in __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_0 ()
#9 0x0203b885 in ___CFXNotificationPost_block_invoke_0 ()
#10 0x0203b7a8 in _CFXNotificationPost ()
#11 0x014f81aa in -[NSNotificationCenter postNotificationName:object:userInfo:] ()
#12 0x01894553 in -[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:] ()
#13 0x0192be3e in -[NSManagedObjectContext(_NSInternalChangeProcessing) _createAndPostChangeNotification:withDeletions:withUpdates:withRefreshes:] ()
#14 0x0188f9b3 in -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] ()
#15 0x0188f269 in -[NSManagedObjectContext processPendingChanges] ()
#16 0x01863948 in _performRunLoopAction ()
#17 0x020449ce in __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ ()
#18 0x01fdb670 in __CFRunLoopDoObservers ()
#19 0x01fa74f6 in __CFRunLoopRun ()
#20 0x01fa6db4 in CFRunLoopRunSpecific ()
#21 0x01fa6ccb in CFRunLoopRunInMode ()
#22 0x02a13879 in GSEventRunModal ()
#23 0x02a1393e in GSEventRun ()
#24 0x008eea9b in UIApplicationMain ()
#25 0x000029ed in main ()
启用NSZombieEnabled不会显示任何内容,