【问题标题】:Core data / NSFetchedResultsController error核心数据/NSFetchedResultsController 错误
【发布时间】:2011-01-02 18:16:39
【问题描述】:

我在处理核心数据/NSFetchedResultsController 时遇到了一些问题。我不完全确定错误在哪里,因为消息很模糊。

当获取的结果控制器没有获取任何对象时,我遇到了插入多个对象的问题。如果我尝试插入多个未获取的对象,则以下代码将崩溃并出现以下错误。如果我用它来插入一个对象,它不会崩溃,如果已经提取了对象,它也不会崩溃。

崩溃发生在 save: 方法上。 NSArray 中的标题,在本例中它包含 5 个字符串。

严重的应用程序错误。例外 在核心数据更改期间被捕获 处理:* -[NSCFArray objectAtIndex:]: 超出索引 (4) 使用 userInfo (null) 限制 (1) * 由于未捕获的异常“NSRangeException”而终止应用程序,原因: '*** -[NSCFArray objectAtIndex:]: 索引 (4) 越界 (1)'

NSEnumerator *titleEnumerator = [titles objectEnumerator];
NSString *title;
NSMutableArray *tasks = [NSMutableArray array];
Todo *todo;

while(title = [titleEnumerator nextObject])
{
    todo = (Todo *)[NSEntityDescription insertNewObjectForEntityForName:@"Todo" inManagedObjectContext:managedObjectContext];
    todo.title = title;
    todo.state = [NSNumber numberWithInteger:TodoStateIncomplete];
    todo.priority = [NSNumber numberWithInteger:TodoPriorityNormal];
    todo.timeStamp = [NSDate date];
    todo.dueDate = [NSDate distantFuture];
}

NSError *error;

if(![managedObjectContext save:&error])
{
    NSLog(@"Unresolved error %@ %@", error, [error userInfo]);
    abort();
}

【问题讨论】:

  • 我已经设法通过一些狡猾的破解来绕过崩溃。在循环中,我检查它是否是第一次。如果是我保存。这就像我一开始只是添加一个对象,以防止在我添加许多对象时它崩溃。这会让我度过难关,但我仍然想知道为什么会发生这种情况,以便我可以正确修复它。

标签: iphone cocoa-touch core-data uikit


【解决方案1】:

就我而言,这个实现很有帮助(感谢彼得):

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

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

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath{
switch (type) {
    case NSFetchedResultsChangeInsert:

        [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
        break;

    case NSFetchedResultsChangeDelete:
        [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
        break;

    case NSFetchedResultsChangeUpdate: {

        NSString *sectionKeyPath = [controller sectionNameKeyPath];
        if (sectionKeyPath == nil){
             break;
        }

        [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];

        break;
    }
    case NSFetchedResultsChangeMove: {

        if (newIndexPath != nil) {

            NSUInteger tableSectionCount = [self.tableView numberOfSections];
            NSUInteger frcSectionCount = [[controller sections] count];
            if (frcSectionCount > tableSectionCount)
                [self.tableView insertSections:[NSIndexSet indexSetWithIndex:[newIndexPath section]] withRowAnimation:UITableViewRowAnimationNone];
            else if (frcSectionCount < tableSectionCount && tableSectionCount > 1)
                [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:[indexPath section]] withRowAnimation:UITableViewRowAnimationNone];


            [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [self.tableView insertRowsAtIndexPaths: [NSArray arrayWithObject:newIndexPath]
                                  withRowAnimation: UITableViewRowAnimationRight];

        }
        else {
            [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:[indexPath section]] withRowAnimation:UITableViewRowAnimationFade];
        }
        break;
    }
}}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type{
switch (type) {
    case NSFetchedResultsChangeInsert:
        if (!((sectionIndex == 0) && ([self.tableView numberOfSections] == 1)))
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
        break;
    case NSFetchedResultsChangeDelete:
        if (!((sectionIndex == 0) && ([self.tableView numberOfSections] == 1) ))
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];

        break;
    case NSFetchedResultsChangeUpdate:
        break;
    case NSFetchedResultsChangeMove:
        break;
}}

【讨论】:

【解决方案2】:

在使用 iPhone SDK 时,Core Data 保存中的此类错误通常指向 NSFetchedResultsController 委托方法中的错误。具体来说,Apple 的示例代码之一是不正确的,并且经常产生此错误。我建议查看您的委托方法并将它们与最新的示例代码进行比较,因为您可能会发现 Apple 已经更新了文档中的示例代码,如果您重新复制他们的代码,这个错误就会消失。

希望对您有所帮助。

【讨论】:

  • 现在(3 年后)Apple Docs 中包含的示例是正确的。我建议使用它。
  • 请链接?查看示例代码,Core Data 上有几个没有特别提到 NSFetchedResultsController 所以我不确定哪个示例被验证为有效?
  • 它在 NSFetchedResultsController 的文档中,标题为“实现表视图数据源方法”部分。
  • 我希望有一个工作示例代码项目,因为似乎仍然存在一些问题。
  • 过去几年我一直在使用该代码片段,没有出现任何问题。如果您遇到问题,我建议您发布一个带有示例代码的 SO 问题,人们可以帮助您。您甚至可以向我发送问题的链接,我很乐意深入研究。
【解决方案3】:

我知道这不太可能是答案,但由于崩溃是在保存时发生的:而且我确实记得曾经有一个奇怪的错误...我的错误是这样修复的,我认为值得一试.

所以,话虽如此,尝试改变

NSError *error;

到

NSError *error = nil;

【讨论】:

  • 虽然这总是一个好建议,但在这种情况下它没有帮助,因为他的代码正在检查来自保存的响应并然后显示错误。在这种情况下,将始终填充错误。
【解决方案4】:

这是来自 Marcus Zarra(Core Data 书籍的作者)的提示:

Core Data error when deleting row in tableView

“尝试中断 objc_exception_throw 并查看抛出异常的方法。这应该有助于追踪它”

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多