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

标签 ios swift core-data

我有一个非常罕见但会导致应用程序崩溃的奇怪错误。我无法重现它,但我终于找到了一份记录此内容的崩溃报告。 (我在下面发布了堆栈跟踪。我使用了屏幕截图,因为这里的引号函数弄乱了格式。那将是不可读的)

所以问题在点击按钮后开始,该按钮调用方法 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 上方淡入淡出 对象存在于数据库中。它使用 NSFetchedResultsController 来管理数据。该表不显示 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% 的时间内正常工作。

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

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

提前致谢!

stack trace

最佳答案

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

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

对于 move,委托(delegate)说明插入之前它从哪里移动,以及插入和删除之后应该插入哪里。当您移动并插入(或移动并删除)时,这可能具有挑战性。我通过将 controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: 中的所有更改保存到三个不同的 indexPath 数组中来修复此问题:插入、删除和更新。当您获得 move 时,在插入数组和删除数组中为其添加一个条目。在 controllerDidChangeContent: 中,删除数组降序排列,插入数组升序排列。然后应用更改 - 先删除,然后插入,然后更新。这将修复当您同时进行移动和插入(或移动和删除)时可能发生的崩溃。

section也是一样的道理。将部分更改保存在数组中,然后按顺序应用更改:删除(降序)、sectionDelete(降序)、sectionInserts(升序)、inserts(升序)、updates(任意顺序)。部分无法移动或更新。

关于ios - 应用程序在更新 UITableView 中显示的 CoreData 模型后崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41789817/

相关文章:

iphone - 自定义字典实现 : Can I Create My Custom affix file?

ios - 向后滑动添加 Action swift 4

ios - 如何从 Facebook + Swift + Parse 获取封面照片

ios - 如何访问不属于 iOS 主包的文件

ios - 从 TableView 中删除单元格

ios - 带有 Action 的 UITableViewCell 按钮

ios - 如何在加载后返回 UIImage

ios - GCD 调度队列是否足以将核心数据上下文限制在单个线程中

iphone - 如何以编程方式将 UIButton 调整为文本大小并保持漂亮的填充?

swift - Swift 编译器中缺少优化级别面板 - 代码生成