【问题标题】:Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'no object at index 3 in section at index 0'由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“索引 0 部分中索引 3 处没有对象”
【发布时间】:2014-09-22 20:50:15
【问题描述】:

您好,我很难修复此错误。

由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“索引 0 部分中索引 3 处没有对象”

当我删除 coredata 中的所有实体并重新获取它时,该错误存在。

调用 API

self.fetchedResultsController = nil;
[NSFetchedResultsController deleteCacheWithName:nil];

[api requestForMenuCategory:@"details" managedObjectContext:self.managedObjectContext delegate:self];

在 API 不获取数据时执行

    if (![self.fetchedResultsController performFetch:&error]) {
    NSLog(@"%@",[error description]);
        }
else{
    NSLog(@"NUMBER OF FETCH %d",[[_fetchedResultsController fetchedObjects] count]);
    [_refreshHeaderView egoRefreshScrollViewDataSourceDidFinishedLoading:self.tableView];
    [self.tableView reloadData];

}

获取次数表示为 0,但我不知道为什么我的 tableview 中仍有数据,过了一会儿它崩溃了

编辑

这是我在节中的行数,我没有节数,因为未实现时默认为 1

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

return [[_fetchedResultsController fetchedObjects] count];

}

编辑 2

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'no object at index 3 in section at index 0'
*** First throw call stack:
(
    0   CoreFoundation                      0x00df65e4 __exceptionPreprocess + 180
    1   libobjc.A.dylib                     0x042a08b6 objc_exception_throw + 44
    2   CoreData                            0x03310cae -[NSFetchedResultsController objectAtIndexPath:] + 398
    3   DogDuck                             0x0014c692 -[TestMenuViewController configureCell:atIndexPath:] + 146
    4   DogDuck                             0x0014c583 -[TestMenuViewController tableView:cellForRowAtIndexPath:] + 227
    5   UIKit                               0x01e2361f -[UITableView _createPreparedCellForGlobalRow:withIndexPath:] + 412
    6   UIKit                               0x01e236f3 -[UITableView _createPreparedCellForGlobalRow:] + 69
    7   UIKit                               0x01e07774 -[UITableView _updateVisibleCellsNow:] + 2378
    8   UIKit                               0x01e05b1f -[UITableView _setNeedsVisibleCellsUpdate:withFrames:] + 171
    9   UIKit                               0x01e1b111 -[UITableView _rectChangedWithNewSize:oldSize:] + 490
    10  UIKit                               0x01e1b6dd -[UITableView setBounds:] + 279
    11  UIKit                               0x01daac17 -[UIScrollView setContentOffset:] + 690
    12  UIKit                               0x01e1c1d1 -[UITableView setContentOffset:] + 314
    13  UIKit                               0x01dc7cae -[UIScrollView(UIScrollViewInternal) _adjustContentOffsetIfNecessary] + 2622
    14  UIKit                               0x01daad82 -[UIScrollView setContentInset:] + 143
    15  UIKit                               0x01e1c302 -[UITableView setContentInset:] + 280
    16  DogDuck                             0x00133be6 -[EGORefreshTableHeaderView egoRefreshScrollViewDataSourceDidFinishedLoading:] + 310
    17  DogDuck                             0x0014c2a8 -[TestMenuViewController doneLoading] + 440
    18  DogDuck                             0x00006192 __66-[BoogieAPI requestForMenuCategory:managedObjectContext:delegate:]_block_invoke + 1266
    19  Foundation                          0x02ce2695 __67+[NSURLConnection sendAsynchronousRequest:queue:completionHandler:]_block_invoke_2 + 151
    20  Foundation                          0x02c42945 -[NSBlockOperation main] + 88
    21  Foundation                          0x02c9b829 -[__NSOperationInternal _start:] + 671
    22  Foundation                          0x02c18558 -[NSOperation start] + 83
    23  Foundation                          0x02c9daf4 __NSOQSchedule_f + 62
    24  libdispatch.dylib                   0x048ac4b0 _dispatch_client_callout + 14
    25  libdispatch.dylib                   0x0489a75e _dispatch_main_queue_callback_4CF + 340
    26  CoreFoundation                      0x00e5ba5e __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 14
    27  CoreFoundation                      0x00d9c6bb __CFRunLoopRun + 1963
    28  CoreFoundation                      0x00d9bac3 CFRunLoopRunSpecific + 467
    29  CoreFoundation                      0x00d9b8db CFRunLoopRunInMode + 123
    30  GraphicsServices                    0x0524c9e2 GSEventRunModal + 192
    31  GraphicsServices                    0x0524c809 GSEventRun + 104
    32  UIKit                               0x01d34d3b UIApplicationMain + 1225
    33  DogDuck                             0x000027cd main + 125
    34  DogDuck                             0x00002745 start + 53
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) 

附加说明 正在调用行的单元格,但 fetchedobject 为 0

【问题讨论】:

  • 你能用numberOfSectionsInTableViewtableView:numberOfRowsInSection: 更新你的问题吗?
  • 您能否更新一下代码的哪一行或哪一部分引发了异常?我打赌它在获取的结果控制器内部,但从异常中不清楚。 UITableView 可以抛出非常相似的异常字符串。堆栈跟踪会很有帮助。
  • @quellish 现在更新了,但是为什么我的tableview在fetchedobject为0时调用cellforrow

标签: ios core-data nsfetchedresultscontroller


【解决方案1】:

问题出在您的 configureCell:atIndexPath 方法中。不幸的是,Core Data Xcode 模板中提供的实现有一些错误。你的崩溃就是其中之一。

NSFetchedResultsController 方法 objectAtIndexPath: 调用起来不是很安全。如果你给它一个超出范围的 NSIndexPath ,它会崩溃,但你看到的只是异常。这在类参考中提到:

如果 indexPath 未在提取结果中描述有效的索引路径,则会引发异常。

这就像访问数组一样:每当您通过索引访问数组时,您应该首先进行边界检查。 objectAtIndexPath: 的边界检查如下所示:

id  result  = nil;
if ([[self.fetchedResultsController sections] count] > [indexPath section]){
    id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:[indexPath section]];
    if ([sectionInfo numberOfObjects] > [indexPath row]){
        result = [self.fetchedResultsController objectAtIndexPath:indexPath];
    }
}

这有点复杂,但很有必要。这解决了异常。

您收到异常的原因是 NSFetchedResultsController 的状态与 tableview 的状态不同步。当您发生崩溃时,tableView 只是询问您的委托方法(numberOfSectionsInTableViewtableView:numberOfRowsInSection: 的行数和节数。当它询问时,NSFetchedResultsController 中有数据,并给出正值(1 节,3 行) . 但是在发生这种情况和您的崩溃之间,由 NSFetchedResultsController 表示的实体已从 NSManagedObjectContext 中删除。现在正在使用过时的 indexPath 参数调用 cellForRowAtIndexPath:

看起来egoRefreshScrollViewDataSourceDidFinishedLoading 正在通过调整滚动视图的内容视图来重建 tableView - 并且 cellForRowAtIndexPath: 被调用 - 你重新获取并重新加载你的 tableView 之前。这需要在 egoRefreshScrollViewDataSourceDidFinishedLoading 做任何事情之前发生。 egoRefreshScrollViewDataSourceDidFinishedLoading 导致 cellForRowAtIndexPath: 被使用过时的索引路径调用。

真正的问题可能在于您的NSFetchedResultsControllerDelegate 方法。当您的实体被删除时,应该调用这些实体以从 tableView 中删除项目。这似乎没有发生在这里。

虽然是简短版本,但请将您的 [self.tableView reloadData]; 上移一行:

[self.tableView reloadData];
[_refreshHeaderView egoRefreshScrollViewDataSourceDidFinishedLoading:self.tableView];

【讨论】:

  • 这样做解决了我的问题 self.tableView reloadData]; [_refreshHeaderView egoRefreshScrollViewDataSourceDidFinishedLoading:self.tableView];关于你说的第一部分....我会把它放在哪里?最后非常感谢你帮助我:D
  • 您可以在您当前调用objectAtIndexPath: 的任何地方进行边界检查。
  • 我建议定义一个这样的私有方法:private func checkIndexPath(indexPath: NSIndexPath) -&gt; Bool{ return self.fetchResultController.sections?.count &gt;= indexPath.section &amp;&amp; self.fetchResultController.sections?[indexPath.section].numberOfObjects &gt;= indexPath.row; }
  • @quellish @Francesco Vadicamo 在两个比较中都必须是 &gt; 而不是 &gt;=...索引从 0 开始等等...
  • 没错@AvielGross。当我回答这个问题时,我一定是脑子里放了个屁。
【解决方案2】:

这是我根据接受的答案编写的辅助方法,但在 Swift 3 中:

func validateIndexPath(_ indexPath: IndexPath) -> Bool {
    if let sections = self.fetchedResultsController?.sections, 
    indexPath.section < sections.count {
       if indexPath.row < sections[indexPath.section].numberOfObjects {
          return true
       }
    }
    return false
}

编辑(使用)

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier(), for: indexPath)

    if self.validateIndexPath(indexPath) {
        configureCell(cell: cell, indexPath: indexPath)
    } else {
        print("Attempting to configure a cell for an indexPath that is out of bounds: \(indexPath)")
    }

    return cell
}

【讨论】:

  • 那去哪儿了?
  • 在您的CoreDataTableViewController 课程中。在检索对象之前从cellForRowAtIndexPath 调用它。
  • 如果“cellForRow”为假,我会返回什么?该方法是一个非可选的返回值。
  • 我已经更新了我的答案,以展示如何使用它。从技术上讲,它不应该是面向用户的,但在极少数情况下,它会覆盖崩溃。
  • 谢谢!稍后我会试一试,看看它是否有效。
猜你喜欢
  • 2019-06-21
  • 1970-01-01
  • 1970-01-01
  • 2018-06-05
  • 2015-05-27
  • 1970-01-01
  • 2014-01-05
相关资源
最近更新 更多