Core data 删除搜索栏表视图中的单元格会导致执行两次删除
我用Core data 删除搜索栏表视图中的单元格会导致执行两次删除,core-data,ios7,tableview,searchbar,Core Data,Ios7,Tableview,Searchbar,我用NSFetchedResultsController实例备份了一个由核心数据备份的表视图。 此表有一个显示筛选数据的搜索栏。搜索栏有一个单独的NSFetchedResultsController(FRC from now)实例 到目前为止,数据是按预期在表视图中获取和显示的,并且在搜索栏的表视图中也正确显示(搜索数据时) 我的问题是,如果我试图删除搜索栏表视图中的单元格,则会出现coredata异常: 错误:严重的应用程序错误。从中捕获了一个异常 调用时NSFetchedResultsCon
NSFetchedResultsController
实例备份了一个由核心数据备份的表视图。
此表有一个显示筛选数据的搜索栏。搜索栏有一个单独的NSFetchedResultsController
(FRC from now)实例
到目前为止,数据是按预期在表视图中获取和显示的,并且在搜索栏的表视图中也正确显示(搜索数据时)
我的问题是,如果我试图删除搜索栏表视图中的单元格,则会出现coredata
异常:
错误:严重的应用程序错误。从中捕获了一个异常
调用时NSFetchedResultsController的委托
-controllerDidChangeContent:。尝试从节0中删除行0,该节在使用userInfo(null)进行更新之前仅包含0行
进一步检查表明,FRC的controllerWillChangeContent
方法在一个单元格删除时被调用两次!。这会导致对同一单元格调用两次deleteRowsAtIndexPaths
(从而导致coredata异常)
再多玩几次,我发现这个问题在搜索后第一次显示搜索栏的表视图时就出现了。(即使返回并删除常规表视图中的单元格,也会出现问题)
我已确保在代码中只调用一次deleteRowsAtIndexPaths
方法(在FRC的didChangeObject
delegate方法中)
现在我不确定要显示哪一个代码,所以我不会把它都说出来。让我知道你需要看哪一个,如果你有什么问题的想法
这是指示表格删除行的代码:
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
DLog(@"didChangeObject type %lu with object %@", (unsigned long)type, anObject);
switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:[self.tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath forTable:self.tableView];
break;
case NSFetchedResultsChangeMove:
[self.tableView deleteRowsAtIndexPaths:[NSArray
arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView insertRowsAtIndexPaths:[NSArray
arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
在删除选定单元格的对象后保存上下文时,将调用此方法
保存上下文的方法:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
[_managedObjectContext deleteObject:[_notesFetcher objectAtIndexPath:indexPath]];
NSError *error;
if (![_managedObjectContext save:&error]) {
DLog(@"Failed deleting object : %@", [error localizedDescription]);
}
}
}
出于某种原因,此方法只调用一次,但对同一单元格使用相同的更改类型(2-Delete)调用两次didChangeObject
更新
在方法didChangeObject中记录堆栈跟踪时,我得到以下结果:
[UITableView AnimatedElectionFrowWithCell:+107 12 UIKit0x01316a35-[UITableViewCell\u swipeDeleteButtonPushed]+70 13 libobjc.A.dylib 0x02346874-[NSObject 性能选择器:withObject:withObject:+77 14 UIKit
0x010a8c8c-[UIApplication sendAction:to:from:forEvent:][108 15 UIKit 0x010a8c18-[UIKit应用 sendAction:toTarget:fromSender:forEvent:+61 16 UIKit
0x011a06d9-[UIControl发送操作:发送到:forEvent:+66 17 UIKit
0x011a0a9c-[UIControl\u发送操作预防:带事件:][577 18 UIKit 0x0119fd4b-[UIControl touchesEnded:withEvent:+641 19 UIKit
0x0141ad7f\u UIgestureRecognitizerUpdate+7166 20 UIKit
0x010e5d4a-[UIWindow\u sendGesturesForEvent:+1291 21 UIKit
0x010e6c6a-[UIWindow sendEvent:+1030 22 UIKit
0x010baa36-[UIApplication sendEvent:+242 23 UIKit
0x010a4d9f_UIApplicationHandleEventQueue+11421
如您所见,表的
swipeDeleteButtonPushed
方法在一次删除操作中被调用两次,正如我前面所述。如果我只按了一次删除按钮,怎么会触发两次?有什么想法吗?您需要始终检查哪个控制器正在调用您的委托方法,并相应地采取行动。同样,您需要检查哪个tableView
正在调用您的委托方法。假设您的viewController
是搜索获取的ResultsController和正常获取的ResultsController
以及搜索表视图和正常表视图的代理
所以你需要一些东西,比如
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
If (tableView == searchTableView) {
// do stuff to searchTableView
} else {
// do stuff to normalTableView
}
}
或者在fetchedResultsController
委托方法中(,我很确定这将是在同一个tableView上得到两个调用的地方)类似于
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
If (controller == searchFetchedResultsController) {
// do stuff to searchTableview
} else {
// do stuff to normaltableview
}
}
您能显示删除表视图行的代码吗?我猜您在搜索和常规视图中使用的是2个FRC,具有相同的控制器。在“更新”方法中,您正在更新同一个表两次。@MartinR I添加了相关的where删除occurs@DanShelly事实上,我使用同一控制器作为两个FRC的委托,但在需要时我确实使用了正确的控制器(搜索和选择单元格会调用正确的序列,并显示正确的数据)我在某个地方读到,self.tableView
始终指向当前表视图(即,如果显示搜索栏的表视图,则self.tableView
将指向该表),并且应该在表的委托方法中使用。@giorashc:这不正确。您必须更新self.tableView
(始终是“主”表视图)或self.searchDisplayController.searchResultsTableView
,具体取决于搜索是否处于活动状态。所以@Dan似乎走上了正确的轨道。我确实检查了显示哪个表视图以使用正确的FRC。即使我从主表视图中删除(搜索并返回主表并删除单元格后),也会出现此问题您确定没有错误地从两个表视图中删除它吗,您应该能够从搜索表视图中删除,并且应该自动从主表视图中删除。请记住,当您删除对象时,两个FetchedResultsController都将调用其委托方法,这似乎正是您上面描述的,但是,您的代码没有检查哪个fetchedresultscontroller正在调用委托方法。上面列出的didChangeObject方法没有检查哪个fetchedresultscontroller正在调用委托方法哇,我肯定是这样做的