Swift Firebase Storage How to Retrieve Image with Unknow Name(Nsuuid)

Swift Firebase Storage How to retrieve image with unknow name(NSUUID)

There can be two ways to go about this :-

1.) Store the Firebase Storage path of users profile_picture in your Firebase database and retrieve every time before you start downloading your profile picture.

2.) Store the file path in CoreData every time your user uploads a profile picture and hit that path every time to get file_Path to where you stored that user's profile_pic .

Storing the path :-

func uploadSuccess(metadata : FIRStorageMetadata , storagePath : String)
{
print("upload succeded!")
print(storagePath)

NSUserDefaults.standardUserDefaults().setObject(storagePath, forKey: "storagePath.\((FIRAuth.auth()?.currentUser?.uid)!)")
//Setting storagePath : (file path of your profile pic in firebase) to a unique key for every user "storagePath.\((FIRAuth.auth()?.currentUser?.uid)!)"
NSUserDefaults.standardUserDefaults().synchronize()

}

Retrieving your path, Every time you start downloading your image :-

let storagePathForProfilePic = NSUserDefaults.standardUserDefaults().objectForKey("storagePath.\((FIRAuth.auth()?.currentUser?.uid)!)") as? String

Note :- i am using currentUser ID, you can use USER SPECIFIC id ,if you want to download multiple users profile pics, all you need to do is put their uid in place.

How to get imageUrl from firebase storage and store in firebase database in Xcode 10 swift 4.2

You can get the download url easily by using the following code inside the closure of your image-upload:

storageRef.downloadURL(completion: { (url, error) in
if let err = error{
// error happened - implement code to handle it
print(err)
} else {
// no error happened; so just continue with your code
print(url?.absoluteString) // this is the actual download url - the absolute string
}

Please note: Don't store the downloadURL on its own as Firebase can change tokens of the downloadURL, I'd suggest to always grab a hold of the full storage path.

I hope I was able to help.

Trying to add an image to Firebase storage then add the image location to a Firestore document

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)
}
}
}

How to download a photo from Firebase Storage and replace the last one for the current user

You should try to call the downloadPhoto() method in the uploadImg() method.

Like this :

func uploadImg() {
name = Auth.auth().currentUser?.displayName
userUid = Auth.auth().currentUser?.uid

guard let img = userImagePicker.image, imageSelected == true else {
print("Image needs to be selected")
return
}

if let imgData = UIImageJPEGRepresentation(img, 0.2) {
let imgUid = NSUUID().uuidString
let metadata = StorageMetadata()
metadata.contentType = "image/jpeg"

Storage.storage().reference().child(imgUid).putData(imgData, metadata: metadata) { (metadata, error) in
if error != nil {
print("Did not upload img")
self.isUploaded = false
} else {
print("Uploaded")
self.isUploaded = true
let downloadURL = metadata?.downloadURL()?.absoluteString
if let url = downloadURL {
self.setUser(img: url)
self.downloadPhoto(user: self.name) // Here add it
}
}
}
}
}

You could too make a function with a piece of code you use in viewDidLoad() and in viewWillAppear() and call this function in this 2 methods for proper code.
Hope it helps.

How to delete a photo from Firebase Storage

To delete an image, you'll need to be able to recreate the path to the image. This means knowing the file name of the image.

When you save your images at the moment, you're assigning each one a random UUID and chucking in the root of the bucket, which isn't helpful from an organisational standpoint. I would create a folder for each user and store the image as something helpful (like profilePic.jpg), as follows:

func uploadImg() {
name = Auth.auth().currentUser?.displayName
userUid = Auth.auth().currentUser?.uid

guard let img = userImagePicker.image, imageSelected == true else {
print("Image needs to be selected")
return
}

if let imgData = UIImageJPEGRepresentation(img, 0.2) {
let metadata = StorageMetadata()
metadata.contentType = "image/jpeg"

// create reference to image location
let profilePicRef = Storage.storage().reference().child("\(userUid!)/profilePic.jpg")
// upload image
profilePicRef.putData(imgData, metadata: metadata) { (metadata, error) in
if error != nil {
print("Didn't upload image in Firebase Storage")
self.isUploaded = false
} else {
print("Uploaded in Firebase Storage")
self.isUploaded = true
let downloadURL = metadata?.downloadURL()?.absoluteString
if let url = downloadURL {
self.setUser(img: url)
self.downloadPhoto(user: self.name)
}
}
}
}
}

Now we can easily find the profile picture, we can easily delete it:

func deleteProfilePic() {
guard let userUid = Auth.auth().currentUser.uid else {
return
}
let pictureRef = Storage.storage().reference().child("\(userUid)/profilePic.jpg")
pictureRef.delete { error in
if let error = error {
// Uh-oh, an error occurred!
} else {
// File deleted successfully
}
}
}

Firebase Upload Images and getting URL issue

If I understood your imageviews, it seems like you have multiple imageviews and for each one the user is able to pick an image from.

With this in mind, your current code handles just one case i.e. myImageView1, but no handling is performed for myImageView2 and myImageView3.

1. Scalable Solution

What you need to do is put your imageviews in an array, then iterate through this array and start uploading each image.

PS: This code isn't tested and is meant to be used as a reference

Create the array holding your imageviews in your viewDidLoad() as shown below

var imageViews: [UIImageView]

override func viewDidLoad()
{
// After initializing them
imageViews = [myImageView1, myImageView2, myImageView3]
}

Since you have a selected variable that keeps track of the imageView that was tapped, we can use it as well to access the respective views in our array as shown below

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) 
{
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage
{
imageViews[selected].image = image
}
else
{
//error
}
self.dismiss(animated: true, completion: nil)
}

In your upload, you want to iterate over imageViews and start uploading each respective image.

@IBAction func upload(_ sender: Any) 
{
let storageRef = Storage.storage().reference().child("images/\(NSUUID().uuidString)/image.png")

for imageView in imageViews
{
if let uploadData = UIImagePNGRepresentation(imageView.image)
{
// continue with your stuff
}
else
{
// Upload Data creation error
}
}
}

2. Non-scalable

Just write multiple if statements in imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) to account for myImageView2 and myImageView3

Two Cents:

I'd recommend the first solution because its not limited by the number of imageviews you currently have. Should you opt to add more in the future, simply append it to the array. The second solution though, leads to multiple if statements and convoluted code.

Edit 1 Bug Discovered

In the above implementation, it assumes that the user will select all the image views in a sequential order i.e. imageView1->imageView2->imageView3->imageView4->imageView5->etc. What if the user selects imageView1->imageView3->imageView5?

Our array will look like this in the above scenario:

[0]->[has image]
[1]->[nil]
[2]->[has image]
[3]->[nil]
[4]->[has image]

The nil segments will result into a crash when trying to create a UIImagePNGRepresentation.

A simple image existence check prior to uploading will resolve this issue.

@IBAction func upload(_ sender: Any) 
{
let storageRef = Storage.storage().reference().child("images/\(NSUUID().uuidString)/image.png")

for imageView in imageViews
{
if imageView.image != nil
{
if let uploadData = UIImagePNGRepresentation(imageView.image)
{
// continue with your stuff
}
else
{
// upload data creation error
}
}

}
}

How to finish the upload of images to Firebase Storage and then save the imageUrl to the Firebase Database

Its happen because success block of your .child("post_Images").child(fileName).put call asynchronously. Rest of code go sync. So your for start uploading photos and after that you are saving URLs to database but urls are empty because you don't wait for finish uploading.

I give you a perfect solution based on DispathGroup

//Create DispatchGroup
let fetchGroup = DispatchGroup()

for i in imagesArray {
guard let uploadData = UIImageJPEGRepresentation(i, 0.3) else { return }

let fileName = NSUUID().uuidString
//Before every iteration enter to group
fetchGroup.enter()
FIRStorage.storage().reference().child("post_Images").child(fileName).put(uploadData, metadata: nil) { (metadata, err) in
if let err = err {
fetchGroup.leave()
return
}

guard let profileImageUrl = metadata?.downloadURL()?.absoluteString else { return }
self.imageUrls.append(profileImageUrl)
//after every completion asynchronously task leave the group
fetchGroup.leave()
}.resume()
}

And know id magic

fetchGroup.notify(queue: DispatchQueue.main) {
//this code will call when number of enter of group will be equal to number of leaves from group
//save your url here
saveToDatabaseWithImageUrl(imageUrls: imageUrls)
}

This solution don't block a thread, everything works asynchronously here.



Related Topics



Leave a reply



Submit