Правильный способ последовательного выполнения асинхронных операций
Мне нужно выполнить асинхронную операцию для каждого элемента в массиве, по одному за раз. Эта операция перезванивает в основной очереди.
func fetchResults(for: array, completion: () -> Void) {
var results: [OtherObject]: []
let queue = DispatchQueue(label: "Serial Queue")
queue.sync {
let group = DispatchGroup()
for object in array {
group.enter()
WebService().fetch(for: object) { result in
// Calls back on main queue
// Handle result
results.append(something)
group.leave()
}
group.wait()
}
}
print(results) // Never reached
completion()
}
Вызов WebService не перезванивает - я думаю, он говорит, что основная очередь заблокирована, но я не могу понять, почему.
3 ответа
Вы должны использовать group.notify()
скорее, чем group.wait()
, поскольку последняя является синхронной блокирующей операцией.
Я также не вижу смысла отправлять в очередь, если вы отправляете только один рабочий элемент один раз.
func fetchResults(for: array, completion: () -> Void) {
var results: [OtherObject]: []
let group = DispatchGroup()
for object in array {
group.enter()
WebService().fetch(for: object) { result in
// Calls back on main queue
// Handle result
results.append(something)
group.leave()
}
}
group.notify(queue: DispatchQueue.main) {
print(results)
completion()
}
}
Может быть, это просто опечатка, но в основном не запустить очередь sync
hronously.
Тогда вместо wait
использование notify
вне (!) цикла и распечатайте results
в очереди.
queue.async {
let group = DispatchGroup()
for object in array {
group.enter()
WebService().fetch(for: object) { result in
// Calls back on main queue
// Handle result
results.append(something)
group.leave()
}
}
group.notify(queue: DispatchQueue.main) {
print(results)
completion()
}
}
Я не думаю, что ваша основная очередь заблокирована, иначе вы, вероятно, имели бы бесконечную загрузку в вашем приложении, как если бы оно падало (в MacOS это точно).
Вот что сработало для меня, может быть, это поможет:
class func synchronize(completion: @escaping (_ error: Bool) -> Void) {
DispatchQueue.global(qos: .background).async {
// Background Thread
var error = false
let group = DispatchGroup()
synchronizeObject1(group: group){ error = true }
synchronizeObject2(group: group){ error = true }
synchronizeObject3(group: group){ error = true }
group.wait() // will wait for everyone to sync
DispatchQueue.main.async {
// Run UI Updates or call completion block
completion(error)
}
}
}
class func synchronizeObject1(group: DispatchGroup, errorHandler: @escaping () -> Void){
group.enter()
WebservicesController.shared.getAllObjects1() { _ in
// Do My stuff
// Note: if an error occures I call errorHandler()
group.leave()
}
}
Если бы я сказал, это может исходить от queue.sync
вместо queue.async
, Но я не эксперт по асинхронным вызовам.
Надеюсь, поможет