我有一个奇怪的错误,非常罕见,但导致应用程序崩溃.我无法重现它,但我终于找到了一份记录此事件的崩溃报告.(我在下面发布了堆栈跟踪.我使用了截图,因为这里的引号函数搞砸了格式化.这将是不可读的)
因此,在点击调用该方法的按钮后,问题就开始了closeButtonTapped
.
该方法应该淡出popup-view
(调用ExtendBitPopupView
)并保存用户输入的文本(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() } } }
因此,它需要用户输入的文本并将其保存为entry.info
数据库.
现在,上下文的一点:该ExtendBitPopupView
是popup
上面一个淡入UITableView
显示所有entry
对象有在数据库中.它使用a NSFetchedResultsController
来管理数据.该表未显示该entry.info
属性.这只能在里面看到ExtendBitPopupView
根据堆栈跟踪,应用程序在调用controllerDidChange
方法时崩溃.我猜它会调用这个方法因为entry
已经改变了.
func controller(_ controller: NSFetchedResultsController, 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%的时间内都能正常工作.
我唯一的观察是,当它发生时,我输入了很多文字.但我不确定这一点,因为到目前为止它只发生了3-4次.
有没有人有任何想法?我不知道我能尝试什么,我不知道如何重现这个bug.如果您需要更多代码,请告诉我们.我刚刚发布了崩溃日志中提到的代码.
提前致谢!
indexPath
是删除和插入之前的索引; newIndexPath
是删除和插入后应用的索引.
对于更新,您不必关心插入和删除之前的位置 - 仅在之后 - 因此newIndexPath
请勿使用indexPath
.这将修复当您更新并同时插入(或更新和删除)时可能发生的崩溃.
对于move
代理人说它是从插入之前移动的位置以及在插入和删除之后应该插入的位置.当您进行移动和插入(或移动和删除)时,这可能具有挑战性.我通过将所有更改保存controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:
到三个不同的数组,插入,删除和更新来修复此问题(您可以使用自定义对象或字典 - 任何适用于您的工作).当您move
在插入数组和删除数组中为它添加条目时.在controllerDidChangeContent:
排序中删除数组降序和插入数组升序.然后应用更改 - 首先删除,然后插入,然后更新.这将解决当您进行移动并同时插入(或移动和删除)时可能发生的崩溃.
处理部分涉及的更多,但它是相同的原则.将节更改保存在数组中,然后按顺序应用更改:删除(降序),sectionDelete(降序),sectionInserts(升序),插入(升序),更新(任何顺序).部分无法移动或更新.