Kunwar Sethi
Kunwar Sethi

Reputation: 27

Wait for image to be uploaded before continuing function with Firebase Storage

I'm trying to upload an image using Firebase Storage. The problem i'm having is when i'm calling my image upload function, the upload task is very slow and it ends up running last in my main function when it is actually called further up.

Is there a way to wait for storageRef.putData to finish before continuing the rest of the function?

Would possibly reducing compression quality from 1 be faster?

Here is my function:

func newImageUrl(){
    let key = self.itemId
    guard let userID = Auth.auth().currentUser?.uid else { return }
    let storageRef = Storage.storage().reference().child(userID).child("SubCategory").child(self.itemTitle!).child(key!).child("ItemImages.jpg")

    guard let imageData = self.itemImage.image!.jpegData(compressionQuality: 1) else { return }

    print("starting image upload!")
    storageRef.putData(imageData, metadata: nil) { (metadata, error) in
        guard let metadata = metadata else {
            return
        }

        storageRef.downloadURL { (url, error) in
            guard let urlStr = url else{
                return
            }
                let urlFinal = (urlStr.absoluteString)
                self.imageFinalUrl = urlFinal
        }
    }
}

UPDATED func --

func newImageUrl(completion:@escaping((String?) -> () )) {
let key = self.itemId
guard let userID = Auth.auth().currentUser?.uid else { completion(nil) ; return }
let storageRef = Storage.storage().reference().child(userID).child("SubCategory").child(self.itemTitle!).child(key!).child("ItemImages.jpg")

guard let imageData = self.itemImage.image!.jpegData(compressionQuality: 1) else { completion(nil) ; return }

print("starting image upload!")
storageRef.putData(imageData, metadata: nil) { (metadata, error) in
    guard let metadata = metadata else {
        return
    }

    storageRef.downloadURL { (url, error) in
        guard let urlStr = url else{
            completion(nil)
            return
        }
        let urlFinal = (urlStr.absoluteString)
        self.imageFinalUrl = urlFinal
        completion(urlFinal)
        }
    }
}

Example main function:

func updateItemDetail(){
    print("this is running 1")
    self.newImageUrl { (str) in
        print(str)
    }
    print("this is running 2")

Console prints:

this is running 1
starting image upload!
this is running 2
Optional("https://firebasestorage.googleapis.com/v0/b/.....etc")

Upvotes: 1

Views: 1220

Answers (2)

MarcusWilliams
MarcusWilliams

Reputation: 562

UPDATED

There is now a method in firebase storage that you can use to put files asynchronsly and therefore you can simply use await to wait for the upload to complete.

e.g

let uploadMetadata = try await storageRef.putDataAsync(imageData, metadata: nil)
//Do whatever you want to after completion

Upvotes: 0

Shehata Gamal
Shehata Gamal

Reputation: 100503

You need a completion

func newImageUrl(completion:@escaping((String?) -> () )) {
    let key = self.itemId
    guard let userID = Auth.auth().currentUser?.uid else { completion(nil) ; return }
    let storageRef = Storage.storage().reference().child(userID).child("SubCategory").child(self.itemTitle!).child(key!).child("ItemImages.jpg")

    guard let imageData = self.itemImage.image!.jpegData(compressionQuality: 1) else { completion(nil) ; return }

    print("starting image upload!")
    storageRef.putData(imageData, metadata: nil) { (metadata, error) in
        guard let metadata = metadata else {
            return
        }

        storageRef.downloadURL { (url, error) in
            guard let urlStr = url else{
                completion(nil)
                return
            }
            let urlFinal = (urlStr.absoluteString)
            self.imageFinalUrl = urlFinal
            completion(urlFinal)
        }
    }
}

Call

newImageUrl { (str) in
  print(str)
  // do your next work here
}

Upvotes: 3

Related Questions