ios - UITableView 使用 NSFetchedResultsController 和 CoreData 意外反弹 beginUpdates()/endUpdates()/performBatchUpdates()
问题描述
UITableView
当行数填满视图时,意外地用beginUpdates()
// using和 CoreData 反弹。重现非常简单。- 从主从应用程序模板(使用 CoreData)创建一个新项目。- 在情节提要中,删除“showDetail”转场。(我们不需要详细视图) - 在 MasterViewController 中,将 segue func 替换为:endUpdates()
performBatchUpdates()
NSFetchedResultsController
prepare()
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let event = fetchedResultsController.object(at: indexPath)
let timestamp = event.timestamp
event.timestamp = timestamp // The idea is to simply update the Event entity.
}
启动应用程序(在 iOS 设备或模拟器中),并添加足够的行来填充视图(在 iPhone SE 中,它是 11 行)。向下滚动视图,然后选择任意行。视图将迅速上下反弹。这是一个错误,还是代码有问题?
解决方案
好的,我可能已经找到了解决方案,请告诉我您的想法。这个想法是处理insert/delete/move
和performBatchUpdates
排除update
它。所以我创建了这个枚举和属性:
enum FetchedResultsChange<Object> {
case insert(IndexPath)
case delete(IndexPath)
case move(IndexPath, IndexPath, Object)
}
var fetchedResultsChanges: [FetchedResultsChange<Event>] = []
并controllerWillChangeContent
变为空:
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {}
didChange
变成:
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch type {
case .insert:
self.fetchedResultsChanges.append(.insert(newIndexPath!))
case .delete:
self.fetchedResultsChanges.append(.delete(indexPath!))
case .update:
configureCell(tableView.cellForRow(at: indexPath!)!, withEvent: anObject as! Event) // So this stays untouched.
case .move:
self.fetchedResultsChanges.append(.move(indexPath!, newIndexPath!, anObject as! Event))
}
}
并controllerDidChangeContent
变成:
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
guard self.fetchedResultsChanges.count > 0 else { return }
tableView.performBatchUpdates({
repeat {
let change = self.fetchedResultsChanges.removeFirst()
switch change {
case .insert(let newIndexPath):
tableView.insertRows(at: [newIndexPath], with: .fade)
case .delete(let indexPath):
tableView.deleteRows(at: [indexPath], with: .fade)
case .move(let indexPath, let newIndexPath, let event):
configureCell(tableView.cellForRow(at: indexPath)!, withEvent: event)
tableView.moveRow(at: indexPath, to: newIndexPath)
}
} while self.fetchedResultsChanges.count > 0
}, completion: nil)
}
所以你怎么看 ?
推荐阅读
- machine-learning - 有什么方法可以理解 word2vec 的输出特征吗?
- express - Nuxt中cookie过期时如何自动注销用户?
- go - 尝试删除文件后发生 sftp 权限被拒绝错误
- c - 了解高效的 CRC-CCITT-16 实施
- python - 如何使用 python 写入 ISO?
- java - 在java中找到数组中相同的薪水
- javascript - 如何从 javascript/nodejs 中的对象数组中获取属性
- python-3.x - 如何防止通过 python3 中的用户输入输入空字符串?
- json - JSON unmarshal 不在我的代码中输出,在 goplayground 中工作
- javascript - 使用主按钮和自身切换所有复选框