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

3

我是一个全新的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.

删除操作似乎能够正确生成 [0,0] 的 NSFetchedResultsChangeDelete,但接着又立即生成了一个 [0,1] 的 NSFetchedResultsChangeUpdate,而 [0,1] 在删除后已经不存在了,因为 [0,1] 看起来现在已经在 [0,0] 中了。
如果没有关联的 Connection 记录,它就可以被成功删除。
我似乎可以通过在 controllerDidChangeContent 中简单地调用 [self.tableView reloadData] 来解决这个问题,而不是实现 begin/end updates 和 didChangeOnject:,但我不认为这是处理这个问题的正确方式。
感谢任何人可以提供的帮助。
2个回答

2

我通过在initWithFetchRequest中向NSFetchedResultsController提供一个非空的sectionNameKeyPath来解决了类似的问题。

然后,我通过以下方式避免了分区:

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

非常烦人。

我的问题是这个错误:

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


这个帮我省了很多麻烦 - 谢谢 :) - Shawn Janas

0
在 - (void)controller:(NSFetchedResultsController *)controller didChangeObject 的顶部:我正在从fetchedResultsController中获取实体。当您刚刚删除对象并需要更新表格时,这会使事情变得混乱。我将实体获取移动到了NSFetchedResultsChangeUpdate部分。这样就避免了崩溃。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接