【问题标题】:Completion gets called soon很快就会调用完成
【发布时间】:2017-08-03 12:43:36
【问题描述】:

我有以下功能。我正在尝试将 allItems 数组传递到 requestItems 的完成块中,但我遇到了崩溃,因为它说它为零。我删除了完成以检查 item 是否有值并且确实存在。

这意味着完成在for循环之前执行。

还有其他方法吗?类似于 Javascript 中的 Promises 将在 for 循环完成时执行完成。

func requestItems(_ data: [String: Any], completion: (Bool, [Item]) -> Void) {

    var allItems = [Item]()

    for i in data["all"] {

        Routes.instance.getRequest(requestType: "items", params: nil, id: someId, completion: { item in

            var it = Item(item["name"] as! String)
            allItems.append(it)

        })

    }

    completion(true, allItems)
}

func getRoutes(requestType: String, parameters: [String: Any]?, id: String, completion: @escaping ([[String:Any]]) -> Void) {

    DispatchQueue.main.async {

        if id == "" {
            self.url = "\(URL_BASE)/\(requestType)"

        } else {
            self.url = "\(URL_BASE)/\(requestType)/\(id)"
        }

        Alamofire.request(self.url, method: .get, parameters: parameters, encoding: JSONEncoding.default, headers: self.headers).responseJSON { response in

            guard response.result.error == nil else {
                print(response.result.error!)
                return
            }

            switch response.result {

            case .success(let JSON):
                let response = [JSON] as! NSArray

                for item in response {

                    if let data = item as? [String: Any] {
                        print(data)
                    }
                }

                completion(response as! [[String : Any]])

            case .failure(let error):
                print("Request failed with error: \(error)")
            }
        }
    }

}

完成处理程序执行得太快,返回一个 nil 项

【问题讨论】:

标签: swift swift3 alamofire


【解决方案1】:

您需要DispatchGroup 才能在异步循环完成时收到通知,例如:

func requestItems(_ data: [String: Any], completion: (Bool, [Item]) -> Void) {

    var allItems = [Item]()
    let group = DispatchGroup()
    for i in data["all"] {
        group.enter()
        Routes.instance.getRequest(requestType: "items", params: nil, id: someId, completion: { item in

            let it = Item(item["name"] as! String)
            allItems.append(it)
            group.leave()

        })
    }
    group.notify(queue: DispatchQueue.main) {
        completion(true, allItems)
    }
}

【讨论】:

  • @SalmanGhumsani 在循环的最后一次迭代调用group.leave()后一次(1x)@
  • 意味着它只会调用一次对吗?最后一次迭代是什么时候?你也能解释一下它的功能如何知道这是最后一次迭代..
  • Yes and Yes (after 最后一次迭代) 简单限定:组计算进入 (+1) 和离开 (-1) 的出现次数,如果计数器达到则退出零。
  • 初始计数 0 并且出现输入 (+1) means count == 1 和离开 (-1) 表示 count == 0 所以它每次都会调用..
  • 不,循环比异步响应快得多,所以它在第一次递减之前递增几次。也许引擎盖下的实际机制有所不同,但这就是原理。请在 Playground 中编写一些代码,添加打印行并证明自己。
【解决方案2】:

您在异步请求getRequest 的完成处理程序之外调用完成处理程序,因此它显然会在函数完成执行之前返回。由于您连续调用多个异步请求,因此简单的完成处理程序无法解决问题。

最好的方法是使用DispatchQueue 仅在所有请求完成后让您的函数返回,或者使用第 3 方框架,例如 PromiseKit 来处理异步函数是具有返回值的普通函数.

【讨论】:

    猜你喜欢
    • 2012-10-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-09
    • 2013-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-11
    相关资源
    最近更新 更多