Ожидание до завершения задачи
Как я могу заставить свой код ждать завершения задачи в DispatchQueue? Нужен ли какой-нибудь CompletionHandler или что-то в этом роде?
func myFunction() {
var a: Int?
DispatchQueue.main.async {
var b: Int = 3
a = b
}
// wait until the task finishes, then print
print(a) // - this will contain nil, of course, because it
// will execute before the code above
}
Я использую Xcode 8.2 и записываю в Swift 3.
Ответы
Ответ 1
Используйте DispatchGroup
для достижения этой цели. Вы можете получить уведомление, когда групповые вызовы enter()
и leave()
сбалансированы:
func myFunction() {
var a: Int?
let group = DispatchGroup()
group.enter()
DispatchQueue.main.async {
a = 1
group.leave()
}
// does not wait. But the code in notify() gets run
// after enter() and leave() calls are balanced
group.notify(queue: .main) {
print(a)
}
}
или вы можете подождать:
func myFunction() {
var a: Int?
let group = DispatchGroup()
group.enter()
// avoid deadlocks by not using .main queue here
DispatchQueue.global(attributes: .qosDefault).async {
a = 1
group.leave()
}
// wait ...
group.wait()
print(a) // you could also 'return a' here
}
Примечание: group.wait()
блокирует текущую очередь (вероятно, основную очередь в вашем случае), поэтому вам нужно dispatch.async
в другой очереди (как в примере кода выше), чтобы избежать тупика.
Ответ 2
В Swift 3 нет необходимости в обработчике завершения, когда DispatchQueue
завершает одну задачу.
Кроме того, вы можете достичь своей цели по-разному.
Один из способов.
var a: Int?
let queue = DispatchQueue(label: "com.app.queue")
queue.sync {
for i in 0..<10 {
print("Ⓜ️" , i)
a = i
}
}
print("After Queue \(a)")
Он будет ждать завершения цикла, но в этом случае ваш почтовый поток будет блокироваться.
Вы также можете сделать то же самое, что и здесь
let myGroup = DispatchGroup()
myGroup.enter()
//// Do your task
myGroup.leave() //// When your task completes
myGroup.notify(queue: DispatchQueue.main) {
////// do your remaining work
}
Последнее. Если вы хотите использовать completeHandler, когда ваша задача завершается с помощью DispatchQueue, вы можете использовать DispatchWorkItem
.
Вот пример использования DispatchWorkItem
let workItem = DispatchWorkItem {
// Do something
}
let queue = DispatchQueue.global()
queue.async {
workItem.perform()
}
workItem.notify(queue: DispatchQueue.main) {
// Here you can notify you Main thread
}
Ответ 3
Использовать группу отправки
dispatchGroup.enter()
FirstOperation(completion: { _ in
dispatchGroup.leave()
})
dispatchGroup.enter()
SecondOperation(completion: { _ in
dispatchGroup.leave()
})
dispatchGroup.wait() //Waits here on this thread until the two operations complete executing.
Ответ 4
Swift 4
Вы можете использовать асинхронную функцию для этих ситуаций. При использовании DispatchGroup()
иногда возможны тупики.
var a: Int?
@objc func myFunction(completion:@escaping (Bool) -> () ) {
DispatchQueue.main.async {
let b: Int = 3
a = b
completion(true)
}
}
override func viewDidLoad() {
super.viewDidLoad()
myFunction { (status) in
if status {
print(self.a!)
}
}
}