Jose G
Jose G

Reputation: 75

How to retrieve the current user image and display in imageView?

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

Answers (1)

Jay
Jay

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

Related Questions