I am trying to implement a user profile view, in which the user chooses a profile image from camera roll and a username. When everything is chosen, the user clicks on a createProfileButton that calls the following function:
#objc func createProfileButtonPressed() {
let user = Auth.auth().currentUser
let uid = Auth.auth().currentUser?.uid
let firebaseStorageRef = Storage.storage().reference().child("profile_picture").child(uid!)
let database = Firestore.firestore()
// settings for disabling warning concerning firestore
let settings = database.settings
settings.areTimestampsInSnapshotsEnabled = true
database.settings = settings
let profileChangeRequest = user?.createProfileChangeRequest()
profileChangeRequest?.displayName = self.usernameTextfield.text
if let profileImage = profilePicture, let imageData = UIImageJPEGRepresentation(profileImage, 0.1) {
firebaseStorageRef.putData(imageData, metadata: nil) { (metadata, error) in
if error != nil {
print("Error:", error!)
return
}
firebaseStorageRef.downloadURL(completion: { (url, error) in
if error != nil {
print("Error:", error!)
return
}
print("Picture URL:", url!)
profileChangeRequest?.photoURL = url
})
}
}
profileChangeRequest?.commitChanges(completion: { (error) in
if error != nil {
print("Error:", error!)
return
}
print("Profile created")
var databaseRef = database.collection("users").addDocument(data: ["uid": uid!, "email": user?.email!, "username": user?.displayName, "profileImageURL": user?.photoURL?.absoluteString], completion: { (error) in
if error != nil {
print("Error storing user", error!)
return
}
print("user successfully stored!")
})
self.navigationController?.popToRootViewController(animated: true)
})
}
I want the users email, username, uid and photoURL stored in a firestore document. However, what I get is this error:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid call to setPhotoURL: after commitChangesWithCallback:.'
This happens after the popToRootViewController function gets called. Why does this error message show up although I want to set the photoURL before I commit the changes?
Just to expand on ekscrypto's comment. Your call to profileChangeRequest?.photoURL = url is taking place within the download callback, thus it going to be run after your call to commitChanges.
You need to put your commitChanges block inside your callback -
if let profileImage = profilePicture, let imageData = UIImageJPEGRepresentation(profileImage, 0.1) {
firebaseStorageRef.putData(imageData, metadata: nil) { (metadata, error) in
if error != nil {
print("Error:", error!)
return
}
firebaseStorageRef.downloadURL(completion: { (url, error) in
if error != nil {
print("Error:", error!)
return
}
print("Picture URL:", url!)
profileChangeRequest?.photoURL = url
profileChangeRequest?.commitChanges(completion: { (error) in
if error != nil {
print("Error:", error!)
return
}
print("Profile created")
var databaseRef = database.collection("users").addDocument(data: ["uid": uid!, "email": user?.email!, "username": user?.displayName, "profileImageURL": user?.photoURL?.absoluteString], completion: { (error) in
if error != nil {
print("Error storing user", error!)
return
}
print("user successfully stored!")
})
self.navigationController?.popToRootViewController(animated: true)
})
})
}
}
Related
enter image description here
#error >> Type of expression is ambiguous without more context.
Auth.auth().createUser(withEmail: email, password: password) { AuthDataResult, error in
// handle error
if let error = error {
print("Failed to create a user with error", error.localizedDescription)
return
}
// set profile image
guard let profileImage = self.plusPhotoButton.imageView?.image else { return }
//upload data
guard let uploadData = profileImage.jpegData(compressionQuality: 0.3) else { return }
// place image in database
let filename = NSUUID().uuidString
let storageRef = Storage.storage().reference().child("profile_image").child(filename)
storageRef.putData(uploadData, metadata: nil, completion: {(metadata, error) in
// handle error
if let error = error {
print("Faild to upload image to firebase storage with error", error.localizedDescription)
}
// profile image URL
guard let profileImageURL = metadata?.downloadURL()?.absoluteString else { return }
//user Id
guard let uid = AuthDataResult?.user.uid else { return }
//guard let fcmToken = messaging.messagin().fcmToken else { return }
let dictionaryValues = ["name": fullName,
"username": username,
"profileImageURL": profileImageURL]
let values = [uid: dictionaryValues]
//save data info to database
Database.database().reference().child("users").updateChildValues(values, withCompletionBlock: { (error, ref) in
print("Successfully created user and saved indformation to database")
})
})
}
i import Firebase but still not working.
I am trying to add an image to Firebase storage and then get the location of that image and store it in a Firestore document with the other user profile data. I am trying to do all of this when the user first creates an account. I was trying to use the image URL to do this but that does not appear to be working. When I run the code below it will sign up a new user and add the photo to Firebase storage but no document gets created in the Firestore database. What am I doing wrong?
#objc func handleSignUp() {
//Signup properties
guard let email = emailTextField.text else { return }
guard let password = passwordTextField.text else { return }
guard let fullName = fullNameTextField.text else { return }
guard let username = usernameTextField.text?.lowercased() else { return }
createUser(email: email,
password: password,
fullName: fullName,
userName: username)
}
func createUser(email: String, password: String, fullName: String, userName: String) {
Auth.auth().createUser(withEmail: email, password: password) { (authResult, error) in
//Handle error
if let error = error {
print("DEBUG: Failed to create user with error: ", error.localizedDescription)
return
}
guard let profileImg = self.plusPhotoBtn.imageView?.image else { return }
guard let uploadData = profileImg.jpegData(compressionQuality: 0.3) else { return }
let userID = Auth.auth().currentUser!.uid
let filename = NSUUID().uuidString
//Storage location for photo in Firebase
let storageRef = Storage.storage().reference().child("profile_images").child(userID).child(filename)
storageRef.putData(uploadData, metadata: nil, completion: { (metadata, error) in
//Handle error
if let error = error {
print("Failed to upload image to Firebase Storage with error", error.localizedDescription)
return
}
guard metadata != nil else { return }
let path = storageRef.fullPath;
guard let username = self.usernameTextField.text?.lowercased() else { return }
storageRef.downloadURL { (url, _) in
let data = ["name": fullName,
"username": username,
"profileImagePath": path,
"email" : email] as [String : Any]
self.addDocument(userData: data)
}
})
}
}
I think you should add the "downloadURL" part inside the "putData".
After completion of the put data process you should try to get the URL or else it will fail.
Try this and see if it works:
#objc func handleSignUp() {
//Signup properties
guard let email = email.text else { return }
guard let password = password.text else { return }
guard let fullName = name.text else { return }
guard let username = name.text?.lowercased() else { return }
createUser(email: email,
password: password,
fullName: fullName,
userName: username)
}
func createUser(email: String, password: String, fullName: String, userName: String) {
Auth.auth().createUser(withEmail: email, password: password) { (authResult, error) in
//Handle error
if let error = error {
print("DEBUG: Failed to create user with error: ", error.localizedDescription)
return
}
guard let profileImg = self.plusPhotoBtn.imageView?.image else { return }
guard let uploadData = profileImg.jpegData(compressionQuality: 0.3) else { return }
let filename = NSUUID().uuidString
//Storage location for photo in Firebase
let storageRef = Storage.storage().reference().child("profile_images").child(filename)
storageRef.putData(uploadData, metadata: nil, completion: { (metadata, error) in
//Handle error
if let error = error {
print("Failed to upload image to Firebase Storage with error", error.localizedDescription)
return
}
guard let metadata = metadata else { return }
guard let username = self.usernameTextField.text?.lowercased() else { return }
storageRef.downloadURL { (url, _) in
guard let downloadURL = url else {
print("DEBUG: Profile image url is nil")
return
}
let data = ["name": fullName,
"username": username,
"profileImageUrl": downloadURL,
"email" : email]
self.addDocument(userData: data)
}
})
}
}
func addDocument(userData: [String: Any]) {
Firestore.firestore().collection("profile_data").addDocument(data: userData) { (err) in
if let err = err {
debugPrint("Error adding document: \(err)")
} else {
self.navigationController?.popViewController(animated: true)
}
}
}
After updating Firebase to Version 4 and correcting all 200 errors, I am left with 2 warnings which make my app crash. I looked up this error and tried the resolution with no success:
storageReference.downloadURLWithCompletion()
I must be doing it wrong:
func setUserInfo(_ user: User!, usersname: String, email: String, password: String, cell: String, data: Data!) {
// Create Path for User Image
let imagePath = "images/riders/\(user.uid)/Profile Pic/userPic.jpg"
// Create image Reference
let imageRef = rDataService.Instance.storageRef.child(imagePath)
// Create Metadata for the image
let metaData = StorageMetadata()
metaData.contentType = "image/jpeg"
// Save the user Image in the Firebase Storage File
imageRef.putData(data as Data, metadata: metaData) { (metaData, error) in
if error == nil {
let changeRequest = user.createProfileChangeRequest()
changeRequest.displayName = usersname
changeRequest.photoURL = metaData?.downloadURL()
changeRequest.commitChanges(completion: { (error) in
if error == nil {
self.saveUser(user, usersname: usersname, email: email, password: password, cell: cell)
} else {
print(error!.localizedDescription)
}
})
} else {
print(error!.localizedDescription)
}
}
}
The error is happening on this line:
changeRequest.photoURL = metaData?.downloadURL()
Edit
After adjustments, getting warning on this line:
if let profilepicMetaData = profilepicMetaData {
error: Value 'profilepicMetaData' was defined but never used; consider replacing with boolean test
App is still crashing:
// Save the user profile Image in the Firebase Storage File
imageRef.putData(data as Data, metadata: profilepicMetaData) { (profilepicMetaData, error) in
if let profilepicMetaData = profilepicMetaData {
imageRef.downloadURL(completion: { (url, error) in
guard let url = url else {
if let error = error {
print(error)
}
return
}
let changeRequest = user.createProfileChangeRequest()
changeRequest.displayName = usersname
changeRequest.photoURL = url
changeRequest.commitChanges(completion: { (error) in
if error == nil {
self.saveUser(user, usersname: usersname, email: email, password: password, year: year, makeAndModel: makeAndModel, cell: cell, plateNo: plateNo)
} else {
print(error!.localizedDescription)
}
})
})
} else {
print(error!.localizedDescription)
}
}
Crash!
You need to use the original storage reference object imageRef to obtain the download url. (please check the comments through the code):
imageRef.putData(data, metadata: profilepicMetaData) {
// use if let to unwrap the metadata returned to make sure the upload was successful. You can use an underscore to ignore the result
if let _ = $0 {
// start the async method downloadURL to fetch the url of the file uploaded
imageRef.downloadURL {
// unwrap the URL to make sure it is not nil
guard let url = $0 else {
// if the URL is nil unwrap the error, print it
if let error = $1 {
// you can present an alert with the error localised description
print(error)
}
return
}
// your createProfileChangeRequest code needs to be run after the download url method completes. If you place it after the closure it will be run before the async method finishes.
let changeRequest = user.createProfileChangeRequest()
changeRequest.displayName = usersname
changeRequest.photoURL = url
changeRequest.commitChanges {
// unwrap the error and print it
if let error = $0 {
// again you might present an alert with the error
print(error)
} else {
// user was updated successfully
self.saveUser(user, usersname: usersname, email: email, password: password, year: year, makeAndModel: makeAndModel, cell: cell, plateNo: plateNo)
}
}
}
} else if let error = $1 {
// present an alert with the error
print(error)
}
}
I am unable to understand what exactly the error is trying to tell me. I tried fixing it by using self and changing classes. Still will not help. Need a guide that could help understand what exactly I am missing or doing wrong.
import UIKit
import Foundation
import Firebase
extension LoginController: UIImagePickerControllerDelegate,UINavigationControllerDelegate{
func handleRegister(){
guard let email = emailTextField.text, let password = passwordTextField.text, let name = nameTextField.text
else {
print("This form is not valid")
return
}
Auth.auth().createUser(withEmail: email, password: password) { (self, error) in
if error != nil {
print(error!)
return
}
guard let uid = self?.uid else{
return
}
//sucessfully authenticated user
let storageRef = Storage.storage().reference()
// On the following line
if let uploadData = UIImagePNGRepresentation(self.profileImageView.image!) {
storageRef.putData(uploadData, metadata: nil, completion: { (metadata, error) in
if error != nil{
print(error)
return
}
})
}
let ref = Database.database().reference(fromURL: "https://bbooks-96cac.firebaseio.com/")
let userReference = ref.child("user").child(uid)
let values = ["name": name, "email": email]
userReference.updateChildValues(values, withCompletionBlock: {
(err, ref) in
if err != nil {
print(err)
return
}
// print("Saved user successfully into firebase DB")
})
}
dismiss(animated: true, completion: nil)
}
}
First, you are misusing the term self (I'm surprised there is no error here). You need a better variable name:
Auth.auth().createUser(withEmail: email, password: password) { (self, error) in
I would change self to user here and throughout what follows:
Auth.auth().createUser(withEmail: email, password: password) { (user, error) in
Second, user is then an Optional so you need to unwrap it:
if let uploadData = UIImagePNGRepresentation(user!.profileImageView.image!) {
I am having some trouble in my code. I gave the permission of "user_photos" in "loginwithreadpermission" but still not getting the users album. I also tried this "fbuserid/albums" but this is also not working for me. Please help me what I am doing wrong.
This is my Login Code:
#IBAction func facebookLogin(sender: AnyObject)
{
let facebookLogin = FBSDKLoginManager()
facebookLogin.logOut()
facebookLogin.logInWithReadPermissions(["email" , "user_photos"], fromViewController: nil) { (facebookResult, facebookError) in
if facebookError != nil {
print("Login Failed. Error: \(facebookError)")
}
else {
if !(facebookResult.isCancelled)
{
let accessToken = FBSDKAccessToken.currentAccessToken().tokenString
if accessToken != nil
{
token = accessToken
let credential = FIRFacebookAuthProvider.credentialWithAccessToken(accessToken)
print("1")
FIRAuth.auth()?.signInWithCredential(credential)
{
(user, error) in
if error != nil
{
print("Error Firebase: \(error)")
}
else
{
if self.userEmails.contains(user!.email!)
{
print("User Already Exist")
NSUserDefaults.standardUserDefaults().setValue(user?.uid, forKey: KEY_UID)
USER_UID = (user?.uid)!
print("id:\(USER_UID)")
LOGIN_FLAG = 1
FaceBookFlag = 1
self.performSegueWithIdentifier("fbLogin", sender: nil)
}
else if user!.email != nil
{
print("Creating a User Data in FB")
var request = FBSDKGraphRequest(graphPath:"me", parameters: ["fields":"email,first_name,age_range"]);
request.startWithCompletionHandler({ (connection, result, error) in
if error == nil
{
print("res: \(result)")
if let dob = result.valueForKey("age_range") as? [String: AnyObject]
{
print("dd: \(dob["min"]!)")
self.dateOfBirth = String(dob["min"]!)
print("dob: \(dob) , date: \(self.dateOfBirth)")
print(" date: \(self.dateOfBirth!)")
}
}
else
{
print("error:: \(error)")
}
let displayName = user?.displayName!.componentsSeparatedByString(" ")
let firstName = displayName![0]
let lastName = displayName![1]
print("url: \(user?.photoURL)")
let profilePicUrl = user?.photoURL
let picture = String(profilePicUrl!)
let userEmail = user!.email!
let _user = ["username": "\(firstName+lastName)","emailAddress": "\(userEmail)", "dateOfBirth": "\(self.dateOfBirth!)"]
ref.child("users").child(user!.uid).setValue(_user)
ref.child("users").child(user!.uid).child("images").setValue([picture])
NSUserDefaults.standardUserDefaults().setValue(user?.uid, forKey: KEY_UID)
USER_UID = (user?.uid)!
LOGIN_FLAG = 1
FaceBookFlag = 1
//Segue to reveal view controller
self.performSegueWithIdentifier("fbLogin", sender: nil)
})
}
}
}
}
}
}
}
}
And This is my Code where I am requesting to give me the albums of current user :
func getAlbums()
{
//for sake of running i hardcoded the FBuserId.
let fbid = "758111074330935"
//169682503464671/photos
let graphRequest = FBSDKGraphRequest(graphPath: "/\(fbid)/albums", parameters: ["fields":"photos,picture"] , HTTPMethod: "GET")
graphRequest.startWithCompletionHandler { (connection, result, error) in
if error != nil
{
print(error)
}
else
{
print("rr:\(result)")
let value = result.valueForKey("data")
print("value:\(value) ... \(result["data"])")
if let graphData = result.valueForKey("data") as? [AnyObject]
{
print("array of Any")
for obj in graphData
{
print("id: \(obj.valueForKey("id")!)")
let id = String(obj.valueForKey("id")!)
self.albumsId.append(id)
//Also save the album link here to.
}
}
}
You have a wrong set of fields for this type of request.
Check this doc to verify the fields that are available: https://developers.facebook.com/docs/graph-api/reference/v2.7/album
In particular, I'm getting the following error (which is self-explained):
{
"error": {
"message": "(#100) Unknown fields: email,first_name.",
"type": "OAuthException",
"code": 100,
"fbtrace_id": "G0POfi9dWkb"
}
}