Firebase Data Retrieval - Edit Annotation
To read data, you want to use the observe attribute from your firebase reference. This returns a snapshot
consisting of your data.
Since your Skatepark
class already has a snapshot constructor, all you'd have to do is pass the snapshot to it and create your object.
reference.child("yourNode").observeSingleEvent(of: .value, with: { (snapshot) in
/* Two things can happen here. Snapshot can either consist of one element or multiple.
To handle this, you want to iterate through the snapshot, create your Skatepark
object and populate it into your global skatepark array.
*/
if snapshot.value is NSNull
{
print("Error Getting Snapshot")
}
else
{
for (child in snapshot.children)
{
let snap = child as! FIRDataSnapshot
let skateObject = Skatepark(child) // this calls the constructor which take snapshot as parameter
globalSkateParkArray.append(skateObject)
}
}
})
To update your values, this is all you need.
Personal Recommendations
- Consider making
coordinate
,name
,subtitle
intovar
instead oflet
. Consider creating a
Skatepark
object first out of the data before sending it to the database. This constructor should do the trickinit(coordinate: CLLocationCoordinate2D, name: String, subtitle: String, type: SkateboardType, editable: Bool)
{
self.coordinate = coordinate
self.name = name
self.subtitle = subtitle
self.type = type
self.editable = editable
}I'd create a
dictionary
variable insideSkatepark
that creates a dictionary from the object. This way I won't have["lat": locationManager.location?.coordinate.latitude, "lng": locationManager.location?.coordinate.longitude, "name": skateTitleText, "subtitle": skateStyleText, "type": (selected - 1), "editable": true]
floating all around my codebase.
So have this in your class
var dictionary: [String:Any]
{
return
[
"lat": coordinate.latitude,
"lng": coordinate.longitude,
"name": title,
"subtitle": subtitle,
"type": type,
"editable": editable
]
}
Every time you'd want a dictionary out of your object, simply use object.dictionary
Retrieve data from Firebase before adding to a map
The second observer in your code is using .childAdded
, which means that closure gets called for each individual child node under clinicas
. This makes it hard to know when you're done with clinics, so I recommend first switching that observer over to .value
, with something like:
clinicas.observe(DataEventType.value) { (snapshots) in
for child in snapshots.children {
let snapshot = child as! DataSnapshot
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)
}
// At this point we're done with all clinics
}
As you'll have notice this code now uses a loop to iterate over snapshots.children
. So we're processing all child nodes of clinicas
in one closure, which makes it much easier to know when we're done.
Now with the above change we have two closures that get called individually, and you have some code that you want to run when both of them are done. There are a few ways to synchronize this code.
The first way is what you've already tried: putting the clinicas.observe
block into the closure of usuarios.child(idUsuarioLogado).observe(
. Now that the clinics observer uses .value
, you'll find that this is much easier to get working.
But I'd like to show an alternative below, where we use two simple flags to determine if both closures are done. For this you will have to put the code that runs after the data is loaded into a separate function, something like this:
func addAnnotationsToMap() }
for oneObject in self.todasAnotacoes {
...
}
}
Now in each of the two closures, we're going to set a flag when they're done. And then at the end of each of the closures, we'll detect whether both flags are set, and then call the new function if we have all data we need.
So at the start of viewDidLoad
we define our two flags:
let isUserLoaded = false
let isClinicsLoaded = false
And then at the end of loading the user:
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) {
addAnnotationsToMap();
}
}
And similar code (setting the isClinicsLoaded
flag) to the other closure.
With these in place, you'll start loading the user data and clinics when the code runs, and then whichever one of them completes last, will call the new addAnnotationsToMap
function.
Another alternative is to use a DispatchGroup
, which is an Apple-specific construct that can also make this much simpler. Read more about it in this answer (and the links from there): Wait until swift for loop with asynchronous network requests finishes executing
Firebase data retrieve and passing it from fragment to new activity not working
In your adapter you dont need to add valueeventlistner , all you need is to pass data to descriptionactivity as shown below
holder.viewmore.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(context, JobDescription.class);
intent.putExtra("JOBTITLE", jobs.getJobtitle);
intent.putExtra("COMPANY", jobs.getcompany);
context.startActivity(intent);
}
});
Related Topics
Pass Data from Tableviewcontroller to Another Tableviewcontroller in Swift
Include Inheritance Constraint in Swift Generic Types
External Library Usage in Xcode
Navigationview Inside a Tabview Swift UI
How to Change an UIimageview into a Custom Cell
Communication Error When Uploading 90 Mb IPA File with Swift to Appstore
Swift- Mkmapkit View Only One City
Scanning Ble Peripheral and Connecting to It
It Is Posible to Load Customise HTML View into Webview in Swift
Swift Displaying The Time or Date Based on Timestamp
How to Add a Storage Reference in Swift for Firestore
Cannot Increment Beyond Endindex
Why Run Loop Is Needed When Using Dispatchqueue.Main.Async in MAC Command Line Tool in Swift