Search code examples
swiftfirebasegoogle-cloud-firestoreuiimagedispatch-async

Downloading images from cloud firestore and adding to user object


i am using firebase cloud firestore, downloading a image from their storage as a profilePicture for a specific user.

I can set the image for the currentUser who is currently Logged in, but when i download and set the picture on all the other users in the database the value on all users UIImage variable is always nil in the array somehow. All the other values on the user is valid so it has to be something with the async?

Im a beginner and appreciate if someone could guide me in the right direction.

I have done this with tableView before and that worked like a charm but cant get it now...

func loadAllUsersFromDB() {
        db.collection("users").getDocuments { (snapshot, error) in
            if error != nil {
                print(error!)
            } else {
                for document in snapshot!.documents {
                    if let snapshotValue = document.data() as? [String : Any] {

                        let userId = snapshotValue["userID"] as? String

                        if userId == self.currentUID {
                            self.currentUser.firstName = snapshotValue["firstname"] as? String
                            self.currentUser.lastName = snapshotValue["lastname"] as? String
                            self.currentUser.email = snapshotValue["email"] as? String
                            self.currentUser.uid = snapshotValue["userID"] as? String
                            self.currentUser.aboutUser = snapshotValue["aboutUser"] as? String
                            self.currentUser.aboutDog = snapshotValue["aboutUserDog"] as? String

                          let photoURL = snapshotValue["photoURL"] as? String

                            if let url = URL(string: photoURL!) {
                                DispatchQueue.global().async {
                                    let data = try? Data(contentsOf: url)
                                    DispatchQueue.main.async {
                                        self.currentUser.profilePhoto = UIImage(data: data!)
                                    }
                                }
                            }
                        } else {

                            self.user.firstName = snapshotValue["firstname"] as? String
                            self.user.lastName = snapshotValue["lastname"] as? String
                            self.user.email = snapshotValue["email"] as? String
                            self.user.uid = snapshotValue["userID"] as? String
                            self.user.aboutUser = snapshotValue["aboutUser"] as? String
                            self.user.aboutDog = snapshotValue["aboutUserDog"] as? String

                            let photoURL = snapshotValue["photoURL"] as? String

                            if let url = URL(string: photoURL!) {
                                DispatchQueue.global().async {
                                    let data = try? Data(contentsOf: url)
                                    DispatchQueue.main.async {
                                        self.user.profilePhoto = UIImage(data: data!)
                                    }
                                }
                            }
                            self.allUsersArray.append(self.user)
                        }
                    }
                }
                self.checkIfUserIsFriends()
            }
            self.filterUsersToShow()
        }
    }

This lines of code works and adding the downloaded photo to currentUser and i am able to set the image from currentUser.profilePhoto to an imageView on another ViewController.

let photoURL = snapshotValue["photoURL"] as? String

                            if let url = URL(string: photoURL!) {
                                DispatchQueue.global().async {
                                    let data = try? Data(contentsOf: url)
                                    DispatchQueue.main.async {
                                        self.currentUser.profilePhoto = UIImage(data: data!)
                                    }
                                }
                            }
                        }

But when i adding users to array the profilePhoto for the user is always nil.

let photoURL = snapshotValue["photoURL"] as? String

                            if let url = URL(string: photoURL!) {
                                DispatchQueue.global().async {
                                    let data = try? Data(contentsOf: url)
                                    DispatchQueue.main.async {
                                        self.user.profilePhoto = UIImage(data: data!)
                                    }
                                }
                            }

Solution

  • You can save only the url in user object and use Kingfisher to manager the download of this image https://github.com/onevcat/Kingfisher

    Example:
    
    import Kingfisher
    
    let resource = ImageResource(downloadURL: URL(fileURLWithPath: "YOUR_URL"))
    self.imageView.kf.indicatorType = .activity
    self.imageView.kf.setImage(with: resource, placeholder: #imageliteral))