从完成处理程序中获取一个 value/object 到它之外的数组中

Get a value/object from a completion handler into an array that is outside of it

我有从服务器获取的数据并使用 JSON 解析该数据。所以我有一个 URL 会话。这个数据被正确解析了,因为我为它使用了一个与接收到的字典中的键相同的结构,但问题是当我 'convert' 这个数据到这个对象时,我无法存储这个对象在完成处理程序范围之外的数组中。

使用的函数:

fileprivate func loadColor(_ urlString: URL?, completionHandler: @escaping (Color) -> Void) {
    if let url = urlString {

        let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
            if error != nil {
                print(error)
            } else {


                do {
                    if let data = data,
                        let color = try JSONSerialization.jsonObject(with: data) as? [String: Any] {
                        guard let color2 = Color(json: color) else
                        {
                            fatalError("something didn't go as planned")
                        }

                        completionHandler(color2)
                    }
                } catch {
                    print("Error deserializing JSON: \(error)")
                }

            }
        }
        task.resume()

    }

}

我在 viewDidLoad() 中调用了这个方法并尝试将其放入这样的数组中:

var colors : [Color] = []

override func viewDidLoad() {
    super.viewDidLoad()

    loadColor(URL(string: "API command here"), completionHandler: { color  in

        self.colors.append(color)
        print("\(self.colors.count)")
    })
    print("\(self.colors.count)")

}

当我在颜色数组上执行追加时,它确实将它添加到数组中,因为在打印计数时它从 0 变为 1,但是当我超出此完成处理程序的范围时,数组再次为空。 我错过了什么?

您的代码看起来完全没问题 - 您的网络调用之外的 print 语句打印 0 值的原因是 API 调用是异步的,因此它将在该打印语句之后完成执行。如果您的数组确实被设置回空数组,那么它一定发生在其他地方。

您可以为调试做的一件事可能是观察该变量,看看它何时像这样设置:

var colors: [Color] = [] {
  didSet {
    //This will be called every time this array is set/changed
    print(colors.count)
  }
}

您甚至可以在 didSet 内的 print 语句上放置一个断点,这样您就可以看到重置数组的痕迹。

不过,我再次怀疑您的代码没有问题,您只是对异步完成时间感到困惑。