在更新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(升序),插入(升序),更新(任何顺序)。 部分不能移动或更新。