Reputation: 75
I want to learn how to properly retrieve the image from Firebase for the current user.I am trying to get the user ImageUrl
from the User
table and use that url to display the image down below but it does not do it and crashes the app. I want to know if I am doing it properly or doing it wrong.
Thank you in advance
func retrieveTheImage() {
let userID = Auth.auth().currentUser?.uid
let retrieveTheUrl = Database.database().reference().child("User").child(userID!)
var capatureUrl :String = ""
retrieveTheUrl.observeSingleEvent(of: .value) { (snapShot) in
if let snapShotValue = snapShot.value as? Dictionary<String,String>{
let url = snapShotValue["ImageUrl"]! /
capatureUrl = url
print(capatureUrl)
}
}
let storage = Storage.storage()
var reference: StorageReference!
reference = storage.reference(forURL: capatureUrl)
reference.downloadURL { (url, error) in
let data = NSData(contentsOf: url!)
let image = UIImage(data: data! as Data )
self.imageUser.image = image
}
}
Upvotes: 0
Views: 372
Reputation: 35657
Your code actually works...almost.
The problem with the code is that Firebase is asynchronous so data only becomes valid within the closure following a firebase call.
So here's what's happening (condensed code)
func retrieveTheImage2() {
let userID = Auth.auth().currentUser?.uid
let retrieveTheUrl = Database.database().reference().child("User").child(userID!)
//code in closure//
}
//code after closure//
--> reference = storage.reference(forURL: capatureUrl) //not valid
reference.downloadURL { (url, error) in
}
}
The code after the closure will execute before the //code in closure//.
That means capatureUrl will be nil because it has not been populated yet. Code is faster than the internet.
To fix that, just move the code that accesses data from Firebase within the closure.
func retrieveTheImage2() {
let userID = Auth.auth().currentUser?.uid
let retrieveTheUrl = Database.database().reference().child("User").child(userID!)
var capatureUrl :String = ""
retrieveTheUrl.observeSingleEvent(of: .value) { (snapShot) in
if let snapShotValue = snapShot.value as? Dictionary<String,String>{
let url = snapShotValue["ImageUrl"]!
capatureUrl = url
print(capatureUrl)
let storage = Storage.storage()
var reference: StorageReference!
reference = storage.reference(forURL: capatureUrl) //will be valid here.
reference.downloadURL { (url, error) in
let data = NSData(contentsOf: url!)
let image = UIImage(data: data! as Data )
self.imageUser.image = image
}
}
}
}
In general, it takes time for data to return from the internet and that's the purpose of Firebase closures - that code executes when the data is valid. So if you want to work with Firebase data, only attempt to access it initially within those closures.
Upvotes: 1