- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我很难找到使用 NSDiffableDataSourceSnapshot reloadItems(_:)
:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Attempted to reload item identifier that does not exist in the snapshot: ProjectName.ClassName
reloadItems
后, TableView 不反射(reflect)更改。
insert
在要更换的项目之后,然后是
delete
的原始项目。没有快照
replace
方法,这正是我所希望的
reloadItems
结果会是。
reloadItems
的特定用途感到困惑的问题,例如
How to update a table cell using diffable UITableView 。所以我以更笼统的形式问,什么实用有没有人发现这种方法?)
struct UniBool : Hashable {
let uuid : UUID
var bool : Bool
// equatability and hashability agree, only the UUID matters
func hash(into hasher: inout Hasher) {
hasher.combine(uuid)
}
static func ==(lhs:Self, rhs:Self) -> Bool {
lhs.uuid == rhs.uuid
}
}
接下来,(假) TableView 和可区分的数据源:
let tableView = UITableView(frame: .zero, style: .plain)
var datasource : UITableViewDiffableDataSource<String,UniBool>!
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
self.datasource = UITableViewDiffableDataSource<String,UniBool>(tableView: self.tableView) { tv, ip, isOn in
let cell = tv.dequeueReusableCell(withIdentifier: "cell", for: ip)
return cell
}
var snap = NSDiffableDataSourceSnapshot<String,UniBool>()
snap.appendSections(["Dummy"])
snap.appendItems([UniBool(uuid: UUID(), bool: true)])
self.datasource.apply(snap, animatingDifferences: false)
}
所以我们的 diffable 数据源中只有一个 UniBool 及其
bool
是
true
.所以现在设置一个按钮来调用这个尝试切换
bool
的操作方法。使用
reloadItems
:
@IBAction func testReload() {
if let unibool = self.datasource.itemIdentifier(for: IndexPath(row: 0, section: 0)) {
var snap = self.datasource.snapshot()
var unibool = unibool
unibool.bool = !unibool.bool
snap.reloadItems([unibool]) // this is the key line I'm trying to test!
print("this object's isOn is", unibool.bool)
print("but looking right at the snapshot, isOn is", snap.itemIdentifiers[0].bool)
delay(0.3) {
self.datasource.apply(snap, animatingDifferences: false)
}
}
}
事情就是这样。我对
reloadItems
说与 UUID 匹配的项目,但其
bool
已切换:“此对象的 isON 为假”。但是当我问快照时,好吧,你有什么?它告诉我它唯一的项目标识符是
bool
仍然是真的。
bool
的新值, 什么是
reloadItems
首先是为了?
reloadItems
;我们崩溃是因为 UniBool 还没有在数据中。我可以通过调用
insert
来解决这个问题。后跟
remove
,这正是我解决它的方法。
reloadItems
是什么?因为,如果不是为了这件事呢?
最佳答案
(我已经就问题中展示的行为提交了一个错误,因为我认为这不是好的行为。但是,就目前情况而言,我认为我可以猜测这个想法的意图。)
当您将快照告诉 reload
某个项目,它不会读入您提供的项目的数据!它只是查看项目,作为识别数据源中已经存在的项目的一种方式,您要求重新加载。
(因此,如果您提供的项目与数据源中已有的项目相同但不是 100% 相同,那么您提供的项目与数据源中已有的项目之间的“差异”将 根本不重要 ;永远不会告诉数据源有什么不同。)
当你然后apply
该快照到数据源,数据源告诉 TableView 重新加载相应的单元格。这会导致再次调用数据源的单元格提供程序函数。
好的,所以调用了数据源的单元格提供程序函数,使用了通常的三个参数——表格 View 、索引路径和来自数据源的数据。但是我们刚才说过,来自数据源的数据没有改变。那么重新加载有什么意义呢?
显然,答案是单元格提供程序函数有望在别处寻找以获取(至少部分)要在新出列的单元格中显示的新数据。您应该有某种单元提供者查看的“后备存储”。例如,您可能正在维护一个字典,其中键是单元标识符类型,值是可能重新加载的额外信息。
这必须是合法的,因为根据定义,单元标识符类型是可散列的,因此可以用作字典键,而且单元标识符在数据中必须是唯一的,否则数据源会拒绝数据(通过崩溃)。并且查找将是即时的,因为这是一本字典。
这是一个完整的工作示例,您可以直接复制并粘贴到项目中。该表格描绘了三个名称以及一个星形,用户可以点击星形来填充或空出星形,表示喜欢或不喜欢。名称存储在 diffable 数据源中,但收藏状态存储在外部后备存储中。
extension UIResponder {
func next<T:UIResponder>(ofType: T.Type) -> T? {
let r = self.next
if let r = r as? T ?? r?.next(ofType: T.self) {
return r
} else {
return nil
}
}
}
class TableViewController: UITableViewController {
var backingStore = [String:Bool]()
var datasource : UITableViewDiffableDataSource<String,String>!
override func viewDidLoad() {
super.viewDidLoad()
let cellID = "cell"
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellID)
self.datasource = UITableViewDiffableDataSource<String,String>(tableView:self.tableView) {
tableView, indexPath, name in
let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath)
var config = cell.defaultContentConfiguration()
config.text = name
cell.contentConfiguration = config
var accImageView = cell.accessoryView as? UIImageView
if accImageView == nil {
let iv = UIImageView()
iv.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: #selector(self.starTapped))
iv.addGestureRecognizer(tap)
cell.accessoryView = iv
accImageView = iv
}
let starred = self.backingStore[name, default:false]
accImageView?.image = UIImage(systemName: starred ? "star.fill" : "star")
accImageView?.sizeToFit()
return cell
}
var snap = NSDiffableDataSourceSnapshot<String,String>()
snap.appendSections(["Dummy"])
let names = ["Manny", "Moe", "Jack"]
snap.appendItems(names)
self.datasource.apply(snap, animatingDifferences: false)
names.forEach {
self.backingStore[$0] = false
}
}
@objc func starTapped(_ gr:UIGestureRecognizer) {
guard let cell = gr.view?.next(ofType: UITableViewCell.self) else {return}
guard let ip = self.tableView.indexPath(for: cell) else {return}
guard let name = self.datasource.itemIdentifier(for: ip) else {return}
guard let isFavorite = self.backingStore[name] else {return}
self.backingStore[name] = !isFavorite
var snap = self.datasource.snapshot()
snap.reloadItems([name])
self.datasource.apply(snap, animatingDifferences: false)
}
}
关于ios - NSDiffableDataSourceSnapshot `reloadItems` 有什么用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64081701/
我很难找到使用 NSDiffableDataSourceSnapshot reloadItems(_:) : 如果我要求重新加载的项目与数据源中已经存在的项目不相等,我会崩溃: Terminating
我想在用户选择联系人(方法didSelect contact)后仅重新加载单个单元格。如果单元格中的项目数量越来越大,该过程就会变得更慢。我还尝试在 DispatchQueue.main.async
我正在尝试创建一个程序,当用户在 UITextField 中输入文本时动态更新 collectoinView。下面是我为实现此目的而创建的扩展 我已经根据您的建议更新了代码以包含插入和删除语句,我仍在
我的单元格有一个从网络下载的图像,因此我需要将单元格的高度设置为动态。图片下载完成后,我将调用 self.collectionView.reloadItems(at: [indexPath]) 来触发
我有一个包含 uicollectionview 的 View Controller .每个collectionview 单元格都包含一个按钮,单击该按钮会在单元格中添加一个新标签。为了扩大每个单元格的
我有一个带有原型(prototype)单元格的 CollectionView。单元格有一个标签。随着时间的推移,标签经常更改值。我使用 collectionView.reloadItems[at: [
我有一个效果很好的 NSOutlineView。如果我更改模型,则当我调用:[self.myOutlineView reloadData] 时,大纲 View 会更新。然而,当我分析我的程序时,似乎有
我一直在使用 UICollectionView.reloadData() 来动态更新我的单元格,这非常有效,但它会导致动画非常笨拙。我连接到 func collectionView(_ collect
我已经针对此行为提出了问题。我想你明白我的意思,如果不明白请问。所以我有一个带有 collectionView 的小演示项目和一个包含整数的数据源。在我的项目中,由于 cpu 使用率较低,我必须通过调
我有一个 collectionView 单元格,它有一个 isExpanded: Bool 属性。当单元格第一次加载时,它被设置为 false 并且它只显示 1 行文本。如果文本有几行那么长,我会在第
我是一名优秀的程序员,十分优秀!