'SwiftUI: upload multiple images to Firebase

Goal: upload 3 images from SwiftUI app to Firebase, with different URL for each.

Problem: I only managed to upload 1.

What I have tried (but didn't work).... :

storagePostRef.putData(image1, image2, image3, metadata: metadata) { (storageMetadata, error) in

Full function bellow:


static func savePostPhoto(
    
    
    //id
    userId: String,
    
    image1: Data,
    image2: Data,
    image3: Data,
    
   // imagesArray : [Data],


    metadata: StorageMetadata,
    storagePostRef: StorageReference,
    onSuccess: @escaping() -> Void,
    onError: @escaping(_ errorMessage: String) -> Void)

  {
    
    let arrayOfImages : [Data] = [image1, image2, image3]

        
    //image storage
    storagePostRef.putData(image1, metadata: metadata) { (storageMetadata, error) in
        
          if error != nil {
              onError(error!.localizedDescription)
              return
          }
        
        //image URL

        storagePostRef.downloadURL { (url, error) in
            
            let image1 = url?.absoluteString
            let image2 = url?.absoluteString
            let image3 = url?.absoluteString

   
        }
    }
    


}




Solution 1:[1]

Each call to putData stores a single image, in the location that you call putData on.

So if you want to store three separate images, you'll have to call putData on three difference StorageReference objects. To then get the three download URLs, you call downloadURL on each of the three StorageReference objects too.

storagePostRef1.putData(image1, metadata: metadata) { (storageMetadata, error) in
  storagePostRef1.downloadURL { (url1, error) in
    let image1 = url?.absoluteString  storagePostRef2.putData(image2, metadata: metadata) { (storageMetadata, error) in
      storagePostRef2.downloadURL { (url2, error) in
        storagePostRef3.putData(image3, metadata: metadata) { (storageMetadata, error) in
          storagePostRef3.downloadURL { (url3, error) in

You can probably clean this up a bit, by creating your own helper function that handles the calls to putData and downloadUrl with a single closure/callback.

Solution 2:[2]

This works pretty well.

 var photoArrayModel = PhotoArrayModel(photoArray: [])
 let userPhotosFirstoreRef = self.ref.document(uid)
 imagesData.enumerated().forEach { index, imageData in
                let userPhotosStorageRef = self.storageRoot.child("user_photos").child(uid).child("image_\(index)")
                userPhotosStorageRef.putData(imageData, metadata: nil) { metaData, error in
                    if error != nil {
                        promise(.failure(.uploadingPhoto))
                    }
                    userPhotosStorageRef.downloadURL { url, error in
                        if error != nil {
                            promise(.failure(.uploadingPhoto))
                        }
                        guard let urlString = url?.absoluteString else { return promise(.failure(.uploadingPhoto))}
                        let photo = PhotoModel(ownerID: uid, imageURL: urlString, timeStamp: Date().millisecondsSince1970)
                        photoArrayModel.photoArray.append(photo)
                        
                        if photoArrayModel.photoArray.count == imagesData.count {
                            do {
                                try userPhotosFirstoreRef.setData(from: photoArrayModel.self)
                                promise(.success(()))
                            } catch {
                                promise(.failure(.uploadingPhoto))
                            }
                            
                        }
                    }
                }
            }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Frank van Puffelen
Solution 2 vebbis