'How can I make multiple uploads to Firebase Storage asynchronous?

I've got an array of data which I want uploading to Firebase Storage in order, so the download urls which are retrieved are in order too.

I've tried to use DispatchGroup and DispatchSemaphore for this, but I'm guessing I've inserted them in incorrect positions in my code, because my print statement which prints the index and the urlString aren't printed in order. How can I fix this?

import Foundation
import FirebaseStorage


func uploadToStorage(dataArray: [Data],
                     completion: @escaping (_ success: Bool, _ urlsAsStringArray: [String]) -> Void) {

    let dispatchGroup = DispatchGroup()
    let dispatchSemaphore = DispatchSemaphore(value: 0)
    let dispatchQueue = DispatchQueue(label: "someTask")
    
    var urlsAsStringArray: [String] = []
    
    
    dispatchQueue.async {
        
        for (index, data) in dataArray.enumerated() {
            
            dispatchGroup.enter()
            dispatchSemaphore.signal()
            
            let imageId = NSUUID().uuidString
            let fileName = "\(imageId).jpg"
            
            let folder = Storage.storage().reference()
                .child("photos")
            
            
            folder.child(fileName).putData(data, metadata: nil) { (metadata, error) in
                
                if let error = error {
                    print("\n \nError with Firebase Storage photo upload:")
                    print(error)
                    
                    dispatchGroup.leave()
                    dispatchSemaphore.wait()
                    
                    completion(false, [])
                    
                    
                } else {
                    print("\n \nSuccess with Firebase Storage photo upload")
                    
                    folder.child(fileName).downloadURL { (url, error) in
                        if let error = error {
                            print("\n \nError with retrieving Firebase Storage photo download URL:")
                            print(error)
                            
                            dispatchGroup.leave()
                            dispatchSemaphore.wait()
                            
                            completion(false, [])
                            
                        } else {
                            if let urlAsString = url?.absoluteString {
                                print("\n \nSuccess with retrieving Firebase Storage photo download URL")
                                print("\n \nPhoto message to be sent to Firebase Firestore has URL link: \(urlAsString)")
                                
                                urlsAsStringArray.append(urlAsString)
                                print("Index is: \(index).  Photo uploaded has url: \(urlAsString)")
                                
                                dispatchGroup.leave()
                                dispatchSemaphore.wait()
                                
                                if index == dataArray.count - 1 {
                                    completion(true, urlsAsStringArray)
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}


Sources

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

Source: Stack Overflow

Solution Source