如何解决重用单元格时,UITableViewDiffableDataSource 单元格提供程序无法获取具有临时 ID 的新添加的托管对象
The sample app 有一个由 UITableViewDiffableDataSource
提供支持的表视图,它从 NSFetchedResultsController
获取数据。您可以通过按加号按钮将字母表中的字母添加到表格视图中。为了实现数据源,我使用了this article。问题是,当我向 Core Data NSFetchedResultsController
添加新项目时,会向单元提供者提供临时 ID。当我向下滚动并且单元提供者必须重用单元时,它无法获取具有临时 ID 的托管对象。然而,当项目被添加到屏幕上的表格视图区域时,它不会发生。
lazy var fetchedResultsController: NSFetchedResultsController<Item> = {
let fetchRequest: NSFetchRequest<Item> = Item.fetchRequest()
let sort = NSSortDescriptor(key: #keyPath(Item.name),ascending: true)
fetchRequest.sortDescriptors = [sort]
let controller = NSFetchedResultsController(
fetchRequest: fetchRequest,managedObjectContext: moc,sectionNameKeyPath: nil,cacheName: nil
)
controller.delegate = self
return controller
}()
func configureDiffableDataSource() {
let diffableDataSource = UITableViewDiffableDataSource<Int,NSManagedObjectID>(tableView: tableView) { (tableView,indexPath,objectID) -> UITableViewCell? in
guard let object = try? self.moc.existingObject(with: objectID) as? Item else {
// Crash happens here.
fatalError("Managed object should be available.")
}
let cell = tableView.dequeueReusableCell(withIdentifier: "cell_id",for: indexPath)
cell.textLabel?.text = object.name
return cell
}
self.diffableDataSource = diffableDataSource
tableView.dataSource = diffableDataSource
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>,didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) {
guard let dataSource = tableView?.dataSource as? UITableViewDiffableDataSource<Int,NSManagedObjectID> else {
assertionFailure("The data source has not implemented snapshot support while it should.")
return
}
var snapshot = snapshot as NSDiffableDataSourceSnapshot<Int,NSManagedObjectID>
let currentSnapshot = dataSource.snapshot() as NSDiffableDataSourceSnapshot<Int,NSManagedObjectID>
let reloadIdentifiers: [NSManagedObjectID] = snapshot.itemIdentifiers.compactMap { itemIdentifier in
guard let currentIndex = currentSnapshot.indexOfItem(itemIdentifier),let index = snapshot.indexOfItem(itemIdentifier),index == currentIndex else {
return nil
}
guard let existingObject = try? controller.managedObjectContext.existingObject(with: itemIdentifier),existingObject.isUpdated else { return nil }
return itemIdentifier
}
snapshot.reloadItems(reloadIdentifiers)
let shouldAnimate = tableView?.numberOfSections != 0
dataSource.apply(snapshot as NSDiffableDataSourceSnapshot<Int,NSManagedObjectID>,animatingDifferences: shouldAnimate)
}
在保存到 Core Data 后立即添加 try! fetchedResultsController.performFetch()
修复了该问题,但是,这是一个蛮力解决方案,会导致对 controller(_:didChangeContentWith:)
委托方法的双重调用,有时还会导致双重动画。在这种情况下,提取应该自动发生。我想知道为什么 Cell Provider 无法获取数据以及如何以有效的方式解决此问题。
@objc func handleAdd() {
// Add item to Core Data.
let context = moc
let entity = Item.entity()
let item = Item(entity: entity,insertInto: context)
item.name = "\(letters[counter])" // Adds letters of the alphabet.
counter += 1
try! context.save()
// Manually fetching right after saving doesn’t seem efficient.
try! fetchedResultsController.performFetch()
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。