在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

    10-08 15:41