Espere hasta que termine de ejecutarse el bucle for rápido con solicitudes de red asincrónicas
Me gustaría que un bucle for in envíe un montón de solicitudes de red a Firebase y luego pase los datos a un nuevo controlador de vista una vez que el método termine de ejecutarse. Aquí está mi código:
var datesArray = [String: AnyObject]()
for key in locationsArray {
let ref = Firebase(url: "http://myfirebase.com/" + "\(key.0)")
ref.observeSingleEventOfType(.Value, withBlock: { snapshot in
datesArray["\(key.0)"] = snapshot.value
})
}
// Segue to new view controller here and pass datesArray once it is complete
Tengo un par de preocupaciones. Primero, ¿cómo espero hasta que finalice el ciclo for y se completen todas las solicitudes de red? No puedo modificar la función observeSingleEventOfType, es parte del SDK de Firebase. Además, ¿crearé algún tipo de condición de carrera al intentar acceder al conjunto de fechas desde diferentes iteraciones del bucle for (espero que tenga sentido)? He estado leyendo sobre GCD y NSOperation pero estoy un poco perdido porque esta es la primera aplicación que creo.
Nota: La matriz de ubicaciones es una matriz que contiene las claves a las que necesito acceder en Firebase. Además, es importante que las solicitudes de red se envíen de forma asincrónica. Solo quiero esperar hasta que se completen TODAS las solicitudes asincrónicas antes de pasar el conjunto de fechas al siguiente controlador de vista.
Puede utilizar grupos de envío para activar una devolución de llamada asincrónica cuando finalicen todas sus solicitudes.
A continuación se muestra un ejemplo que utiliza grupos de distribución para ejecutar una devolución de llamada de forma asincrónica cuando han finalizado varias solicitudes de red.
override func viewDidLoad() {
super.viewDidLoad()
let myGroup = DispatchGroup()
for i in 0 ..< 5 {
myGroup.enter()
Alamofire.request("https://httpbin.org/get", parameters: ["foo": "bar"]).responseJSON { response in
print("Finished request \(i)")
myGroup.leave()
}
}
myGroup.notify(queue: .main) {
print("Finished all requests.")
}
}
Producción
Finished request 1
Finished request 0
Finished request 2
Finished request 3
Finished request 4
Finished all requests.
veloz 3 o 4
Si no te importan los pedidos , usa la respuesta de @paulvs , funciona perfectamente.
De lo contrario, por si acaso alguien quiere obtener el resultado en orden en lugar de activarlos al mismo tiempo, aquí está el código.
let dispatchGroup = DispatchGroup()
let dispatchQueue = DispatchQueue(label: "any-label-name")
let dispatchSemaphore = DispatchSemaphore(value: 0)
dispatchQueue.async {
// use array categories as an example.
for c in self.categories {
if let id = c.categoryId {
dispatchGroup.enter()
self.downloadProductsByCategory(categoryId: id) { success, data in
if success, let products = data {
self.products.append(products)
}
dispatchSemaphore.signal()
dispatchGroup.leave()
}
dispatchSemaphore.wait()
}
}
}
dispatchGroup.notify(queue: dispatchQueue) {
DispatchQueue.main.async {
self.refreshOrderTable { _ in
self.productCollectionView.reloadData()
}
}
}