У меня есть функция, делающая несколько HTTP-запросов с помощью Alamofire. Я хочу дождаться завершения всех из них, чтобы вернуть значение. Однако он застревает в 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
можно сделать.
Вы никогда не должны использовать один и тот же поток для вызова wait
и leave
.
Самое простое решение — заменить использование wait
на notify
.
group.notify(queue: DispatchQueue.main) {
completion(resreturn)
}
Вы должны избегать использования wait
в целом. Особенно, если вы уже используете обработчик завершения и методу не нужно ждать.
Это то, что я тоже использую. Просто к вашему сведению - вызовы group.enter() вызываются сразу после других, потому что замыкания возвращаются немедленно.