更新 UITableView 中显示的 CoreData 模型后应用程序崩溃 [英] App crashes after updating CoreData model that is being displayed in a UITableView
问题描述
我有一个非常罕见的奇怪错误,但会导致应用程序崩溃.我无法重现它,但我终于找到了一份记录此问题的崩溃报告.(我在下面发布了堆栈跟踪.我使用了屏幕截图,因为这里的引号函数弄乱了格式.那将是不可读的)
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屋!