0

When a user taps their profile photo they have an option to select a new photo. I want to store the photo into my Storage and Database and update the view as soon as the imagePickerController is dismissed the new image shows on the screen, however nothing changes in the database and after logging in and out the old profile image is still there.

enter image description here

var user: User!

var dataBaseRef: DatabaseReference!{
    return Database.database().reference()
}
var storageRef: StorageReference!{
    return Storage.storage().reference()
}

func updatePhoto() {
    let user = Auth.auth().currentUser
    let newPhoto = profileImage.image

    let imgData = UIImageJPEGRepresentation(newPhoto!, 0.7)!
    let imagePath = "profileImage\(user.uid)/userPic.jpg"
    let imageRef =  storageRef.child(imagePath)
    let metadata = StorageMetadata()
    metadata.contentType = "image/jpeg"
    imageRef.putData(imgData, metadata: metadata) { (metadata, error) in
        if error == nil {
    let changeRequest = Auth.auth().currentUser?.createProfileChangeRequest()

            if let photoURL = metadata!.downloadURL(){

                changeRequest?.photoURL = photoURL
            }

            changeRequest?.commitChanges(completion: { (error) in
        if error == nil{

            let user = Auth.auth().currentUser

            let userInfo = ["firstLastName": self.nameOld,  "email": self.emailString, "password": self.passwordOld, "location": self.locationOld, "interests": self.interestsOld, "biography": self.bioOld, "uid": self.uid, "photoURL": String(describing: user?.photoURL!)]

            let userRef = self.dataBaseRef.child("users").child((user?.uid)!)
            userRef.setValue(userInfo)
            let credential = EmailAuthProvider.credential(withEmail: self.emailString, password: self.passwordOld)

                    user?.reauthenticate(with: credential) { error in
                        if let error = error {

                            print(error)
                            // An error happened.
                        } else {
                            print("AUTHENTICATED")
                            // User re-authenticated.
                        }
                    }
            print("user info set")

        }

    })
        }}}



func loadUserInfo(){


    let userRef = dataBaseRef.child("users/\(Auth.auth().currentUser!.uid)")

    userRef.observe(.value, with: { (snapshot) in

        let user = Users(snapshot: snapshot)

        if let username = user.firstLastName{
            self.name.text = username
            self.nameOld = username
        }


        if let userLocation = user.location{
            self.location.text = userLocation
            self.locationOld = userLocation
        }
        if let bio = user.biography{
            self.biog.text = bio
            self.bioOld = bio
        }
        if let interests = user.interests{
            self.interests.text = interests
            self.interestsOld = interests 
        }

        if let imageOld = user.photoURL{


            //  let imageURL = user.photoURL!



            self.storageR.reference(forURL: imageOld).getData(maxSize: 10 * 1024 * 1024, completion: { (imgData, error) in

                if error == nil {
                    DispatchQueue.main.async {
                        if let data = imgData {
                            self.profileImage.image = UIImage(data: data)
                        }
                    }

                }else {
                    print(error!.localizedDescription)

                }

            }


            )}


    }) { (error) in
        print(error.localizedDescription)
    }


}

override func viewDidLoad() {
    super.viewDidLoad()
    setGestureRecognizersToDismissKeyboard()
    loadUserInfo()
}



   func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    if let image = info[UIImagePickerControllerOriginalImage]  as? UIImage{
        self.profileImage.image = image
        updatePhoto()
    }
    else if let image = info[UIImagePickerControllerEditedImage] as? UIImage {
        self.profileImage.image = image
        updatePhoto()
    }
    self.dismiss(animated: true, completion: nil)
}
hg56
  • 185
  • 1
  • 3
  • 16
  • does `print("user info set")` get called? – Peter Tao Jan 10 '18 at 09:02
  • No it doesn't get called – hg56 Jan 10 '18 at 09:05
  • add `print(error)` right after `changeRequest?.commitChanges(completion: { (error) in` and let me know what is printed – Peter Tao Jan 10 '18 at 09:06
  • [Generic] Creating an image format with an unknown type is an error – hg56 Jan 10 '18 at 09:08
  • That's why it is not being saved to the database. The error is not nil, and thus userRef.setValue is not called. There is likely something in the `commitChanges` function that needs fixing. – Peter Tao Jan 10 '18 at 09:10
  • Im sorry that was already showing in the console before I added print(error), adding print(error) didn't add anything else – hg56 Jan 10 '18 at 09:11
  • Put debug points in code and step over every line of code. Check values of every variable and constants that you have doubt about. – Sagar Chauhan Jan 10 '18 at 19:25

1 Answers1

0

From apple documentation, UIImagePickerControllerEditedImage: Specifies an image edited by the user and UIImagePickerControllerOriginalImage: Specifies the original, uncropped image selected by the user. If the user does not edit the selected image, you should also call updatePhoto() function in order to upload the selected photo:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    if let image = info[UIImagePickerControllerOriginalImage]  as? UIImage{
        self.profileImage.image = image
        updatePhoto()
    }
    else if let image = info[UIImagePickerControllerEditedImage] as? UIImage {
        self.profileImage.image = image
        updatePhoto()
    }
    self.dismiss(animated: true, completion: nil)
}
  • as soon as a new photo is selected I am getting Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value on let imagePath = "profileImage\(user.uid)/userPic.jpg" inside my updatePhoto(), any idea what may be causing this? – hg56 Jan 10 '18 at 18:56
  • Make sure to be authenticated. In this instruction your are unwrapping the value of user.uid. If you are not authenticated, then user.uid will return nil. – Karim Dahmani Jan 10 '18 at 19:03
  • I authenticated. Now the uid, email, and password go blank. And photo gives error Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'URL scheme must be one of gs://, http://, or https:// – hg56 Jan 10 '18 at 19:20
  • You should unwrap optional values correctly. You can take a look at this answer https://stackoverflow.com/questions/25195565/how-do-you-unwrap-swift-optionals. In addition, if you want to save the url of your photo in the database, you can get it by writing `photoURL.absoluteString()`. Replace `"photoURL": String(describing: user?.photoURL!)`by `"photoURL": photoURL.absoluteString())` – Karim Dahmani Jan 10 '18 at 19:43
  • the photoUrl changed successfully however email, password and uid keep going to blank values. – hg56 Jan 10 '18 at 20:05
  • Replace `self.emailString` by `user.email` and `self.uid`by `user.uid`. The password should not be saved in the database. It is not a good practice. There are no access to the password from the firebase user object. However, you can get it from the textfield where you tap your password. – Karim Dahmani Jan 10 '18 at 20:09