0

When my user signs up, they are using a profile image that goes directly to firebase. The image uploads into firebase storage the properly but once it appears in the database the profile image URL is missing also in the debug area the image link is showing up as optional. What should I change in this code to properly upload the image link into the firebase database?

  if let AuthData = AuthDataResult {
                  print(AuthData.user.email)
                      var dict : Dictionary < String, Any> = [
                        "uid": AuthData.user.uid,
                          "username": self.UsernameTextField.text!,
                      "email": AuthData.user.email,

"ProfileImageUrl": "",
                      ]
    let storage = Storage.storage()
    let storageRef = storage.reference()
    let imageName = UUID().uuidString
    let imageReference = Storage.storage().reference().child(imageName)

    //2. Compress quality
    if let uploadData = self.ProfileImage.image?.jpegData(compressionQuality: 0.5){

    //3. Save image as .jpeg
    let metaDataForImage = StorageMetadata()
    metaDataForImage.contentType = "image/jpeg"

    //4. Add the data to Firebase Storage
    imageReference.putData(uploadData, metadata: metaDataForImage) { (meta, err) in
        if let err = err{
            print(err.localizedDescription)
        } else {
            //5. Retrieving the image URL
            imageReference.downloadURL { (url, err) in
                if let err = err{
                    print(err.localizedDescription)
                } else {
                    //6. Print the complete URL as string
                    let urlString = url?.absoluteString
                    print(urlString)
                }

                Database.database().reference().child("users").child(AuthData.user.uid).updateChildValues(dict, withCompletionBlock: { (error,ref) in
                    if error == nil {
                        print("Done")
                        return
                    }
  • I don't see where you're writing the URL to the database. Make sure to do that **inside** the closure that gets called when `imageReference.downloadURL { (` completes, so **inside* the same code block as step 6. – Frank van Puffelen Mar 13 '20 at 22:50
  • @FrankvanPuffelen After attempting to format this code (it's somewhat incomplete). I think the issue is here `.updateChildValues(dict` because there is no `dict` data populated with the url to write. Also, if there is an error (say `AuthData.user.uid` is invalid) the error is not being trapped and the code will just silently fail. – Jay Mar 14 '20 at 15:04
  • Hey Jay, I have a feeling the code is still incomplete. If it isn't: your guess sounds good indeed, so please write an answer if you feel you can help OP. – Frank van Puffelen Mar 14 '20 at 15:37
  • It’s no error with the AuthData @Jay –  Mar 14 '20 at 18:46
  • But there is no error handling code so how to you know? The code is not well formatted but it appears all of that code is pat of the `AuthData` var? Best Practice is to name variables with lower case... Upper case Class and Struct names. – Jay Mar 15 '20 at 12:45

2 Answers2

1

It appears that all of the code in the question is within the AuthData var.

The issue is caused by one of the key: value pairs within the dict var being an empty string. I'll shorten this up a bit to highlight the issue. Here's the original code with my added comments:

 if let AuthData = AuthDataResult {
    var dict : Dictionary < String, Any> = [
        "uid": AuthData.user.uid,
        "username": self.UsernameTextField.text!,
        "email": AuthData.user.email,
        "ProfileImageUrl": "",  // <--- Profile ImageUrl is an empty string
    ]

    imageReference.putData(uploadData, metadata: metaDataForImage) { (meta, err) in
        if let err = err{
        } else {
            imageReference.downloadURL { (url, err) in
                if let err = err{
                } else {
                    let urlString = url?.absoluteString
                }

                //The ProfileImageUrl key: value pair within the **dict** var is an
                //  empty string at this point, so no url is written.
                let dbRef = Database.database().reference()
                let usersRef = dbRef.child("users").child(AuthData.user.uid)
                usersRef.updateChildValues(dict, withCompletionBlock: { (error,ref) in
                   if error == nil {
                      print("Done")
                      return
                   }
                   //note that if an error occurs, the code silently fails

To fix, populate the dict with the data you want written.

Here's a corrected section of the code which includes error checking and populating the ProfileImageUrl with the download url and then writing it to Firebase.

imageReference.downloadURL { (url, error) in
    if let err = error {
        print(err.localizedDescription)
        return
    }

    guard let validUrl = url else {
        print("url was not valid")
        return
    }

    let urlString = validUrl.absoluteString
    dict["ProfileImageUrl"] = urlString //update the dict with the url

    let dbRef = Database.database().reference()
    let usersRef = dbRef.child("users").child(AuthData.user.uid)
    usersRef.updateChildValues(dict, withCompletionBlock: { error, ref in
        if let err = error {
            print(err.localizedDescription)
            return
        }

        print("Successfully wrote auth data and url")
    })
}
Jay
  • 34,438
  • 18
  • 52
  • 81
0

My educated guess is that you're writing the user information to the database when the upload hasn't completed, or the download URL hasn't yet been retrieved. Both uploading and requesting the download URL are asynchronous operations, meaning that any code that depends on them being completed needs to be inside the closure that gets executed when the operation completes (or be called from there).

let storage = Storage.storage()
let storageRef = storage.reference()
let imageName = UUID().uuidString
 let imageReference = Storage.storage().reference().child(imageName)

 //2. Compress quality
 if let uploadData = self.ProfileImage.image?.jpegData(compressionQuality: 0.5){

     //3. Save image as .jpeg
     let metaDataForImage = StorageMetadata()
     metaDataForImage.contentType = "image/jpeg"

     //4. Add the data to Firebase Storage
     imageReference.putData(uploadData, metadata: metaDataForImage) { (meta, err) in
         if let err = err{
             print(err.localizedDescription)
         }
         else{
             //5. Retrieving the image URL
             imageReference.downloadURL { (url, err) in
                 if let err = err{
                     print(err.localizedDescription)
                 }
                 else{
                     //6. Print the complete URL as string
                     let urlString = url?.absoluteString
                     print(urlString)

                     // 7. Write the URL to the database here <--
                 }
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807