在更新UITableView中显示的CoreData模型后,应用程序崩溃

我有一个奇怪的错误是非常罕见的,但会导致应用程序崩溃。 我不能复制它,但我终于find了一个崩溃报告logging这一点。 (我发布了下面的堆栈跟踪,我使用了一个截图,因为这里的引用函数搞乱了格式化,这是不可读的)

所以问题开始后点击一个button,调用方法closeButtonTapped

此方法应该淡出popup-view (称为ExtendBitPopupView )并保存用户input的文本(我的数据模型之一的details属性)。 这是closeButtonTapped方法:

 func closeButtonTapped(tap: UITapGestureRecognizer) { fadeOut { // fadeOut(completion:) just fades out the UI if self.infoTextView.text != "Enter details..." { self.entry.info = self.infoTextView.text self.appDelegate.saveContext() } } } 

所以它需要用户input的文本并将其作为entry.info保存到数据库中。

现在,有一点上下文: ExtendBitPopupView是一个popup ,在UITableView上方显示,显示数据库中的所有entry对象。 它使用NSFetchedResultsController来pipe理数据。 该表不显示entry.info属性。 这只在ExtendBitPopupView可见

根据堆栈跟踪,应用程序在调用controllerDidChange方法时崩溃。 我想它调用这个方法,因为一个entry已经改变。

 func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) { switch type { case .insert: tableView.insertRows(at: [newIndexPath!], with: .automatic) case .delete: tableView.deleteRows(at: [indexPath!], with: .automatic) case .update: // I guess this case is being used let cell = tableView.cellForRow(at: indexPath!) as! BitCell let entry = fetchedResultsController.object(at: indexPath!) cell.configure(entry: entry) case .move: tableView.deleteRows(at: [indexPath!], with: .automatic) tableView.insertRows(at: [newIndexPath!], with: .automatic) } } 

在崩溃日志中提到了第224行。 这是这条线:

 let cell = tableView.cellForRow(at: indexPath!) as! BitCell 

我无法弄清楚为什么应用程序可能会在这个时候崩溃。 此外,它99%的时间正常工作。

我唯一的观察是,当它发生时,我input了相当多的文本。 但是我不确定,因为它到目前为止只发生过3-4次。

有没有人有任何想法? 我不知道我可以尝试什么,我不知道如何重现这个错误。 如果你需要更多的代码,请告诉我。 我刚刚发布了崩溃日志中提到的代码。

提前致谢!

堆栈跟踪

indexPath是删除和插入前的索引; newIndexPath是应用删除和插入后的索引。

对于更新你不关心它是在插入和删除之前 – 只有之后 – 所以使用newIndexPath而不是indexPath 。 这将修复当您更新并同时插入(或更新和删除)时可能发生的崩溃。

对于move ,委托人说,从插入前的位置移动到插入和删除后插入的位置。 当你有一个移动和插入(或移动和删除),这可能是具有挑战性的。 我通过保存来自controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:所有更改controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:为三个不同的数组,插入,删除和更新(您可以使用自定义对象或字典 – 无论您controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:工作)。 当你做一个move的时候,在插入数组和删除数组中添加一个条目。 在controllerDidChangeContent:按降序对插入数组进行升序sorting。 然后应用更改 – 首先删除,然后插入,然后更新。 这将修复当你有一个移动和同时插入(或移动和删除)时可能发生的崩溃。

处理部分是多一点,但这是相同的原则。 删除数组中的部分更改,然后按顺序应用更改:删除(降序),sectionDelete(降序),sectionInserts(升序),插入(升序),更新(任何顺序)。 部分不能移动或更新。