更新 UITableView 中显示的 CoreData 模型后应用程序崩溃 [英] App crashes after updating CoreData model that is being displayed in a UITableView

查看:23
本文介绍了更新 UITableView 中显示的 CoreData 模型后应用程序崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a strange bug that is extremely rare but causes the app to crash. I can't reproduce it but I finally found a crash report documenting this. (I posted the stack trace below. I used a screenshot, as the quotes function here messed up the formatting. That would be unreadable)

所以问题是在点击按钮后开始的,该按钮调用方法closeButtonTapped.

So the problem begins after tapping a button, which calls the method closeButtonTapped.

这个方法应该淡出一个popup-view(称为ExtendBitPopupView)并保存用户输入的文本(details我的数据模型之一).这是 closeButtonTapped 方法:

This method is supposed to fade out a popup-view (called ExtendBitPopupView) and save the text the user entered (details attribute of one of my data models). That's the closeButtonTapped method:

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 保存到数据库中.

So it takes the text the user entered and saves it as entry.info to the database.

现在,稍微介绍一下上下文:ExtendBitPopupView 是一个 popup,它淡入显示所有 条目的 UITableView 上方 对象存在于数据库中.它使用 NSFetchedResultsController 来管理数据.该表不显示 entry.info 属性.这仅在 ExtendBitPopupView

Now, a little bit of context: The ExtendBitPopupView is a popup that fades in above a UITableView that displays all entry objects there are in the database. It's using a NSFetchedResultsController to manage the data. The table does not show the entry.info attribute. That is only visible inside the ExtendBitPopupView

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

According to the stack trace, the app crashes while calling the controllerDidChange method. I guess it calls this method because an entry has changed.

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 行.这是这一行:

Line 224 is mentioned in the crash log. It's this line:

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

我不明白为什么应用程序此时会崩溃.此外,它在 99% 的情况下都能正常工作.

I can't figure out why the app could crash at this moment. Also, it does work correctly 99% of the time.

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

My only observation is that when it happens, I typed in quite a lot of text. But I'm not sure about this, as it only happened like 3-4 times so far.

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

Does anyone have any ideas? I don't know what I can try and I don't know how to reproduce this bug. If you need any more code, let me know. I just posted the code that is mentioned in the crash log.

提前致谢!

推荐答案

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

indexPath is the index BEFORE the deletes and inserts are applied; newIndexPath is the index AFTER the deletes and inserts are applied.

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

For updates you don't care where it was BEFORE the inserts and delete - only after - so use newIndexPath not indexPath. This will fix crashes that can happen when you an update and insert (or update and delete) at the same time.

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

For move the delegate is saying where it moved from BEFORE the inserts and where it should be inserted AFTER the inserts and deletes. This can be challenging when you have a move and insert (or move and delete). I fixed this by saving all the changes from controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: into three different indexPath arrays: insert, delete and update. When you get a move add an entry for it in both the insert array and in the delete array. In controllerDidChangeContent: sort the delete array descending and the insert array ascending. Then apply the changes - first delete, then insert, then update. This will fix crashes that can happens when you have a move and insert (or move and delete) at the same time.

对于section来说也是一样的道理.将部分更改保存在数组中,然后按顺序应用更改:删除(降序)、sectionDelete(降序)、sectionInserts(升序)、插入(升序)、更新(任何顺序).部分不能移动或更新.

It is the same principle for sections. Save the sections changes in arrays, and then apply the changes in order: deletes (descending), sectionDelete (descending), sectionInserts (ascending), inserts(ascending), updates (any order). Sections can't move or be updated.

这篇关于更新 UITableView 中显示的 CoreData 模型后应用程序崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆