调度组等待永远卡住

Dispatch Group wait stuck forever

我有一个使用 Alamofire 发出多个 HTTP 请求的函数。我想等待所有这些都完成才能 return 一个值。但是,它卡在 dispatch.wait()

class func getActionField(fieldid: String, completion: @escaping (_ res: [String: [Double]]) -> Void) {
        var resreturn: [String: [Double]] = ["temperature":[], "humidity":[], "ph":[], "light":[]]
        let dispatch = DispatchGroup()
        dispatch.enter()
        Alamofire.request(url + "aktionsdaten/temperatur/" + fieldid, method: .get).responseJSON{ response in
            resreturn["temperature"] = response.result.value as! NSArray as? [Double] ?? [0.0,0.0]
            dispatch.leave()
        }
        dispatch.enter()
        Alamofire.request(url + "aktionsdaten/light/" + fieldid, method: .get).responseJSON{ response in
            resreturn["light"] = response.result.value as! NSArray as? [Double] ?? [0.0,0.0]
            dispatch.leave()
        }
        dispatch.enter()
        Alamofire.request(url + "aktionsdaten/ph/" + fieldid, method: .get).responseJSON{ response in
            resreturn["ph"] = response.result.value as! NSArray as? [Double] ?? [0.0,0.0]
            dispatch.leave()
        }
        dispatch.enter()
        Alamofire.request(url + "aktionsdaten/feuchtigkeit/" + fieldid, method: .get).responseJSON{ response in
            resreturn["humidity"] = response.result.value as! NSArray as? [Double] ?? [0.0,0.0]
            dispatch.leave()
        }
        dispatch.wait()
        completion(resreturn)
    }

您已正确设置所有这些,在完成所有异步任务后使用完成处理程序。唯一的问题是您错误地使用了 DispatchGroup 模式。这是正确的模式(这是伪代码):

let group = DispatchGroup()
group.enter()
queue1.async {
    // ... do task here ...
    group.leave()
}
group.enter()
queue2.async {
    // ... do task here ...
    group.leave()
}
group.enter()
queue3.async {
    // ... do task here ...
    group.leave()
}
// ... more as needed ...
group.notify(queue: DispatchQueue.main) {
    // finished! call completion handler or whatever
}

假设 getActionField 正在主队列上调用,并且了解 Alamofire 在主队列上调用其完成块(在我看来是糟糕的设计),你会 运行 陷入僵局因为对 wait 的调用现在阻塞了主队列,所以可以进行对 leave 的 none 调用。

您绝不能使用同一个线程来调用 waitleave

最简单的解决方案是将 wait 的使用替换为 notify

group.notify(queue: DispatchQueue.main) {
    completion(resreturn)
}

您一般应避免使用 wait。特别是如果您已经在使用完成处理程序并且方法不需要等待。