reloadItems(_:)
的用法时遇到了困难:
如果我要求重新加载的项目与已存在于数据源中的项目不相等,则会出现以下错误:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Attempted to reload item identifier that does not exist in the snapshot: ProjectName.ClassName
但是,如果该项目与已存在于数据源中的项目相等,那么“重新加载”它有什么意义呢?
你可能会认为第二个问题的答案是:好吧,可能存在项目标识符对象的某些其他方面,它们不属于其可比性,但确实反映在单元格接口中。但我发现这并不是真的;调用reloadItems
后,表视图不会反映更改。
因此,当我想要更改项目时,我最终使用快照进行替换项之后进行insert
,然后删除原始项。没有快照replace
方法,这就是我希望reloadItems
能够实现的内容。
(我在Stack Overflow上搜索了这些术语,发现很少 —— 主要只是一些关于reloadItems
的特定用途的问题,例如How to update a table cell using diffable UITableView。所以我更一般地问,有人发现这种方法有什么实际用途吗?)
好的,没有什么比有一个最小化可重现示例来玩耍更好的了,所以这里有一个。
创建一个普通的iOS项目,使用其模板ViewController,并将此代码添加到ViewController中。
我会逐个解释。首先,我们有一个结构体,它将用作我们的项目标识符。 UUID是唯一的部分,因此相等性和哈希性仅取决于它:
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
}
}
接下来,是伪造的表视图和可差异数据源:
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)
}
所以在我们的可区分数据源中只有一个UniBool,它的bool
是true
。现在设置一个按钮来调用此操作方法,该方法尝试通过使用reloadItems
来切换bool
值:
@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)
}
}
}
所以,问题来了。我使用UUID匹配的项目调用
reloadItems
,但其bool
被切换为“此对象的isON为false”。但是当我询问快照时,它告诉我,它唯一的项目标识符的bool
仍然为true。
这就是我要问的。如果快照不会获取bool
的新值,那么reloadItems
一开始是用来做什么的呢?
显然,我可以只替换一个不同的UniBool,即具有不同UUID的UniBool。但是,我不能调用reloadItems
;因为该UniBool尚未在数据中,所以我们会崩溃。我可以通过调用insert
,然后是remove
来解决这个问题,这正是我如何解决它的方法。
但我的问题是:如果不是用于这个目的,那么reloadItems
有什么作用?
diffable data source
呢?我可以使用旧的cellForRowAt
实现。 - mattreconfigureItems
方法,它似乎有与reloadItems
相同的问题,我不得不将我的模型从结构体更改为类才能使其正常工作。文档说reconfigureItems
应该用于更新现有单元格的内容,而不是用新单元格替换它们,但到目前为止我发现的唯一区别是reloadItems
会触发单元格的prepareForReuse
,而reconfigureItems
则不会。 - PatrickDotStar