I'm building an application where a user can store companies information (like name, address, latitude, longitude to a Firebase real-time database).
With that information, those companies are then presented in a map as annotations.
My viewDidLoad is shown below
override func viewDidLoad() {
super.viewDidLoad()
// Definitions
let autenticacao = Auth.auth()
let idUsuarioLogado = (autenticacao.currentUser?.uid)!
let database = Database.database().reference()
let usuarios = database.child("usuarios")
let clinicas = database.child("clinicas")
// Map - User location
self.mapa.delegate = self
self.gerenciadorLocalizacao.delegate = self
self.gerenciadorLocalizacao.desiredAccuracy = kCLLocationAccuracyBest
self.gerenciadorLocalizacao.requestWhenInUseAuthorization()
self.gerenciadorLocalizacao.startUpdatingLocation()
// retrieve user information
usuarios.child(idUsuarioLogado).observe(DataEventType.value) { (snapshot) in
let dados = snapshot.value as? NSDictionary
let emailUsuario = dados?["email"] as! String
let nomeUsuario = dados?["nome"] as! String
let perfilUsuario = dados?["perfil"] as! String
let idUsuario = snapshot.key
let usuario = Usuario(email: emailUsuario, nome: nomeUsuario, uid: idUsuario, perfil: perfilUsuario)
print("User profile \(perfilUsuario)")
}
// Clinicas listeners
clinicas.observe(DataEventType.childAdded) { (snapshot) in
let dados = snapshot.value as? NSDictionary
//print("Dados na leitura \(dados)")
let clinica = Clinica()
clinica.identificador = snapshot.key
clinica.nome = dados?["nome"] as! String
clinica.endereco = dados?["endereco"] as! String
clinica.cidade = dados?["cidade"] as! String
clinica.cep = dados?["cep"] as! String
clinica.estado = dados?["estado"] as! String
clinica.latitude = dados?["latitude"] as! String
clinica.longitude = dados?["longitude"] as! String
clinica.urlImagem = dados?["urlImagem"] as! String
clinica.idImagem = dados?["idImagem"] as! String
self.clinicasR.append(clinica)
}
// add annotations to the map
for oneObject in self.todasAnotacoes {
print("Oneobj \(oneObject)")
let umaAnotacao = MinhaAnotacao()
var oneObjLoc: CLLocationCoordinate2D = CLLocationCoordinate2DMake(oneObject.objLat, oneObject.objLong)
umaAnotacao.coordinate = oneObjLoc
umaAnotacao.title = oneObject.objName
umaAnotacao.subtitle = oneObject.objDesc
umaAnotacao.category = oneObject.objCat
self.anotacaoArray.append(umaAnotacao)
self.mapa.addAnnotations(self.anotacaoArray)
}
}
My viewDidLoad is "structured" in 4 main blocks (even though they run in a different order given they are asynchronous):
- Definition;
- Retrieve user profile;
- Retrieve companies information (name, latitude, longitude);
- Add annotations to the map.
As those are asynchronous functions, they run in different order and this is what is causing trouble to me. note: There is still one piece missing here that is to feed all annotations to the variable todasAnotacoes which I'll do once I can retrieve data before triggering add annotation "block".
As annotation info comes from the firebase database, I should only have it executed once the clinicas.observe(DataEventType.childAdded) { (snapshot) in
is concluded.
As is today, the sequence Xcode runs is:
- Definitions
- Add annotations;
- retrieve data from firebase with companies details
I've tried adding the add annotation block to the closure, adding a dispatchqueue but none of those really worked. I also did a lot os search in stackoverflow but I couldn't find anything that i can use (or I wasn't able to understand).
So, in summary I need to run the add annotations after retrieving all data from Firebase.
Any ideas on how I could do that?
EDIT 1 - Final code with the suggested updates
override func viewDidLoad() {
super.viewDidLoad()
// Retrieving Logger user data and hidding "add" button if applicable
ProgressHUD.show("Carregando...")
let autenticacao = Auth.auth()
let idUsuarioLogado = (autenticacao.currentUser?.uid)!
let database = Database.database().reference()
let usuarios = database.child("usuarios")
var isUserLoaded = false
var isClinicsLoaded = false
usuarios.child(idUsuarioLogado).observe(DataEventType.value) { (snapshot) in
let dados = snapshot.value as? NSDictionary
let emailUsuario = dados?["email"] as! String
let nomeUsuario = dados?["nome"] as! String
let perfilUsuario = dados?["perfil"] as! String
let idUsuario = snapshot.key
let usuario = Usuario(email: emailUsuario, nome: nomeUsuario, uid: idUsuario, perfil: perfilUsuario)
isUserLoaded = true
if (isUserLoaded && isClinicsLoaded) {
self.addAnnotationsToMap();
}
//print("\(usuario.email) e \(usuario.nome) e \(usuario.uid) e \(usuario.perfil)")
}
// Option to code above
/*if Auth.auth().currentUser != nil {
if let uid = (Auth.auth().currentUser?.uid) {
let database = Database.database().reference()
let usuarios = database.child("usuarios").child(uid)
usuarios.observe(.value) { (snapshot) in
let dados = snapshot.value as? NSDictionary
let emailUsuario = dados?["email"] as! String
let nomeUsuario = dados?["nome"] as! String
let perfilUsuario = dados?["perfil"] as! String
let idUsuario = snapshot.key
let usuario = Usuario(email: emailUsuario, nome: nomeUsuario, uid: idUsuario, perfil: perfilUsuario)
print("Got here \(usuario.email) e \(usuario.nome) e \(usuario.uid) e \(usuario.perfil)")
if perfilUsuario != "admin" {
self.navigationItem.rightBarButtonItems?.remove(at: 1)
print("Disable + Button")
}
}
}
}*/
// Map - User location
self.mapa.delegate = self
self.gerenciadorLocalizacao.delegate = self
self.gerenciadorLocalizacao.desiredAccuracy = kCLLocationAccuracyBest
self.gerenciadorLocalizacao.requestWhenInUseAuthorization()
self.gerenciadorLocalizacao.startUpdatingLocation()
let clinicas = database.child("clinicas")
// Clinicas listeners
clinicas.observe(DataEventType.value) { (snapshots) in
for child in snapshots.children {
let snapshot = child as! DataSnapshot
print("Clinicas Mapeadas - end")
let dados = snapshot.value as? NSDictionary
//print("Dados na leitura \(dados)")
let clinica = Clinica()
clinica.identificador = snapshot.key
clinica.nome = dados?["nome"] as! String
clinica.endereco = dados?["endereco"] as! String
clinica.cidade = dados?["cidade"] as! String
clinica.cep = dados?["cep"] as! String
clinica.estado = dados?["estado"] as! String
clinica.latitude = dados?["latitude"] as! String
clinica.longitude = dados?["longitude"] as! String
clinica.urlImagem = dados?["urlImagem"] as! String
clinica.idImagem = dados?["idImagem"] as! String
self.clinicasR.append(clinica)
self.todasAnotacoes.append((objLat: Double(clinica.latitude) as! CLLocationDegrees, objLong: Double(clinica.longitude) as! CLLocationDegrees, objName: clinica.nome, objDesc: clinica.endereco, objId: clinica.identificador))
}
isClinicsLoaded = true
if (isUserLoaded && isClinicsLoaded) {
self.addAnnotationsToMap();
}
}
/* NOT IN USE FOR NOW
let latitude = Double(-23.623558)
let longitude = Double(-46.580787)
let localizacao: CLLocationCoordinate2D = CLLocationCoordinate2D.init(latitude: latitude, longitude: longitude)
let span: MKCoordinateSpan = MKCoordinateSpan.init(latitudeDelta: 0.01, longitudeDelta: 0.01)
let regiao = MKCoordinateRegion.init(center: localizacao, span: span)
self.mapa.setRegion(regiao, animated: true)*/
ProgressHUD.dismiss()
}
// add annotations to the map
func addAnnotationsToMap() {
anotacaoArray = []
for oneObject in self.todasAnotacoes {
for oneObject in self.todasAnotacoes {
// print("Oneobj \(oneObject)")
let umaAnotacao = MinhaAnotacao()
var oneObjLoc: CLLocationCoordinate2D = CLLocationCoordinate2DMake(oneObject.objLat, oneObject.objLong)
umaAnotacao.coordinate = oneObjLoc
umaAnotacao.title = oneObject.objName
umaAnotacao.subtitle = oneObject.objDesc
umaAnotacao.identicadorMapa = oneObject.objId
self.anotacaoArray.append(umaAnotacao)
print("Annotation added \(todasAnotacoes.count) - end")
}
self.mapa.addAnnotations(self.anotacaoArray)
self.todasAnotacoes = []
self.anotacaoArray = []
// print("Annotations added 2 - end")
}
}