由于自引用连接,从 UITableView 删除时应用程序崩溃

Posted

技术标签:

【中文标题】由于自引用连接,从 UITableView 删除时应用程序崩溃【英文标题】:App is crashing when deleting from UITableView due to self referencing connection 【发布时间】:2010-10-19 23:26:45 【问题描述】:

我是 iPhone 开发的新手(以及此处发布的第一个问题),并且有点坚持使用 Core Data 和 Table Views。

简而言之,当我从 UITableView 中删除一行时,我的应用程序崩溃了,因为 NSFetchedResultsChangeUpdate 对由于自引用表上的级联删除而已被删除的记录调用。

这里是数据模型的描述:

有两个实体; PersonConnection

Person 包含 name(字符串)、connections(与 的多个关系Connection->source,级联删除规则)和connectedby(与Connection->connection的多关系,级联删除规则)

Connection 包含 relationship(字符串)、source(与Person->connections,使删除规则无效)和connection(与Person->connectedby的关系,使删除规则无效)

这个想法是有两个人通过关系联系在一起(例如母亲儿子

在我的 TableViewController 中,我实现了以下内容:

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller 
[self.tableView beginUpdates];

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath 
    UITableView *tableView = self.tableView;
    Person *person = nil;
    switch(type) 
    case NSFetchedResultsChangeInsert:
        [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];         
        break;
    case NSFetchedResultsChangeDelete:
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
        break;
    case NSFetchedResultsChangeUpdate:
        person = (Person *)[fetchedResultsController objectAtIndexPath:indexPath];
        [self configureCell:(PersonTableViewCell *)[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
        break;          
    case NSFetchedResultsChangeMove:
        person = (Person *)[fetchedResultsController objectAtIndexPath:indexPath];
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
        [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
        break;
     

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller 
    [self.tableView endUpdates];

以下是我创建的用于测试的示例记录:

Person *person1 = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:self.managedObjectContext];
[person1 setName:[NSString stringWithFormat: @"Tommy"]];

Person *person2 = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:self.managedObjectContext];
[person2 setName:[NSString stringWithFormat: @"Jane"]];

Connection *connection = [NSEntityDescription insertNewObjectForEntityForName:@"Connection" inManagedObjectContext:managedObjectContext];
[connection setConnection:person2];
[connection setSource:person1];
[connection setRelationship:[NSString stringWithFormat:@"Mother"]];

Connection *connection2 = [NSEntityDescription insertNewObjectForEntityForName:@"Connection" inManagedObjectContext:managedObjectContext];
[connection2 setConnection:person1];
[connection2 setSource:person2];
[connection2 setRelationship:[NSString stringWithFormat:@"Son"]];

当我删除 indexPath[0,0] 处的记录时,即本例中的 Jane,因为视图是按名称排序的,我生成以下错误:

2010-10-19 16:09:01.461 HelpMe[6324:207] 
Serious application error.  
Exception was caught during Core Data change processing.  
This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification.
*** -[NSMutableArray objectAtIndex:]: index 1 beyond bounds [0 .. 0] with userInfo (null)
Detected an attempt to call a symbol in system libraries that is not present on the iPhone:
_Unwind_Resume called from function -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] in image CoreData.

删除似乎为 indexPath [0,0] 正确生成了 NSFetchedResultsChangeDelete,但随后也立即为 [0,1] 生成了 NSFetchedResultsChangeUpdate ,因为 [0,1] 现在似乎在 [0,0] 中,因此不再存在删除后。

没有关联的Connection记录,删除就好了。

我似乎可以通过简单地在 controllerDidChangeContent 上调用 [self.tableView reloadData] 而不是实现开始/结束更新和 didChangeOnject 来解决这个问题:但我不认为这是处理这个问题的正确方法。

感谢任何人提供的任何帮助。

【问题讨论】:

【参考方案1】:

我通过向 NSFetchedResultsController(在 initWithFetchRequest 中)提供非零 sectionNameKeyPath 解决了类似的问题。

然后我使用以下方法避开了部分:

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section 
    return @"";

很烦人。

仅供参考,我的问题是这个错误:

严重的应用程序错误。一个 从委托中捕获了异常 NSFetchedResultsController 在一个 调用 -controllerDidChangeContent:。 * -[NSMutableArray objectAtIndex:]:空数组的索引 0 超出范围 与 userInfo (null)

【讨论】:

这让我非常头疼 - TY :)【参考方案2】:

在 - (void)controller:(NSFetchedResultsController *)controller didChangeObject 的顶部:我正在从 fetchedResultsController 中提取实体。好吧,当您刚刚删除对象并需要更新表时,这确实会搞砸事情。我将实体提取移动到NSFetchedResultsChangeUpdate 部分。这让我没有崩溃。

【讨论】:

以上是关于由于自引用连接,从 UITableView 删除时应用程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章

从 UITableView 中删除自定义视图

从数据库中删除未引用的数据

在 UITableView 上延迟 reloadData

有没有办法从UITableView中删除分隔线?

从 UItableview 删除一行时崩溃

从 UITableView 中删除行会导致部分标题问题?