Esperando hasta que termine la tarea
¿Cómo podría hacer que mi código espere hasta que DispatchQueue
finalice la tarea? ¿Necesita algún controlador de finalización o algo así?
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.
}
Estoy usando Xcode 8.2 y escribiendo en Swift 3.
Si necesita ocultar la naturaleza asincrónica de myFunction
la persona que llama, use DispatchGroup
s para lograrlo. De lo contrario, utilice un bloque de finalización. Encuentre muestras para ambos a continuación.
Muestra de grupo de despacho
Puedes recibir una notificación cuando las llamadas enter()
y el grupo leave()
estén equilibrados:
func myFunction() {
var a = 0
let group = DispatchGroup()
group.enter()
DispatchQueue.main.async {
a = 1
group.leave()
}
// does not wait. But the code in notify() is executed
// after enter() and leave() calls are balanced
group.notify(queue: .main) {
print(a)
}
}
o puedes esperar:
func myFunction() {
var a = 0
let group = DispatchGroup()
group.enter()
// avoid deadlocks by not using .main queue here
DispatchQueue.global(qos: .default).async {
a = 1
group.leave()
}
// wait ...
group.wait()
print(a) // you could also `return a` here
}
Nota : group.wait()
bloquea la cola actual (probablemente la cola principal en su caso), por lo que debe hacerlo dispatch.async
en otra cola (como en el código de muestra anterior) para evitar un punto muerto .
Muestra de bloque de finalización
func myFunction(completion: @escaping (Int)->()) {
var a = 0
DispatchQueue.main.async {
let b: Int = 1
a = b
completion(a) // call completion after you have the result
}
}
// on caller side:
myFunction { result in
print("result: \(result)")
}
En Swift 3, no es necesario un controlador de finalización cuando DispatchQueue
finaliza una tarea. Además puedes lograr tu objetivo de diferentes maneras.
Una forma es esta:
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)")
Esperará hasta que finalice el ciclo, pero en este caso su hilo principal se bloqueará.
También puedes hacer lo mismo así:
let myGroup = DispatchGroup()
myGroup.enter()
//// Do your task
myGroup.leave() //// When your task completes
myGroup.notify(queue: DispatchQueue.main) {
////// do your remaining work
}
Una última cosa: si desea utilizar completeHandler cuando su tarea se complete usando DispatchQueue, puede usar DispatchWorkItem
.
Aquí hay un ejemplo de cómo usarlo 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
}