在Swift中异步更改字典/其他集合的惯用正确方法是什么?
编码时经常会出现以下几种情况:
func loadData(key: String, dict: inout [String: String]) {
// Load some data. Use DispatchQueue to simulate async request
DispatchQueue.main.async {
dict[key] = "loadedData"
}
}
var dict = [String:String]()
for x in ["a", "b", "c"] {
loadData(key: x, dict: &dict)
}
在这里,我正在异步加载一些数据,并将其添加到作为参数传入的集合中。但是,由于
inout
的复制语义,该代码无法在Swift中编译。我想到了两个解决此问题的方法:
惯用的正确方法是哪种?
我看到在这个问题中对此主题进行了一些讨论:Inout parameter in async callback does not work as expected。但是,没有一个答案集中在如何真正解决问题上,只是为什么现在的代码不起作用。
最佳答案
这个(hack)似乎有效:
func loadData(key: String, applyChanges: @escaping ((inout [String: String]) -> Void) -> Void) {
DispatchQueue.main.async {
applyChanges { dict in
dict[key] = "loadedData"
}
}
}
...
for x in ["a", "b", "c"] {
loadData(key: x) { $0(&dict) }
}
虽然不是惯用语...我想说的是,惯用语是不异步地改变事物。您始终可以在完成处理程序中将要进行的更改返回给集合。对于字典,这可能是另一本字典,然后将其与原始字典一起merge
。