1
votes

I am currently trying to download multiple files upon user request for a game. My goal is to have it download only one file at a time and stop executing code until that file has finished downloading.

My code is an array of JSON objects, in each contains a path for where to download them to(path) and the URL of the file. I am looping through the array and using AlamoFire to download them with a .downloadProgress closure.

Alamofire.download(
json["url"].stringValue,
method: .get,
to: destination).downloadProgress(closure: { (Alamoprogress) in
info.stringValue = "Downloading: " + filename
progress.doubleValue = Alamoprogress.fractionCompleted * 100
}).response(completionHandler: { (DefaultDownloadResponse) in
})

To try to make sure it only downloaded a single file at a time, I set up a DispatchQueue and moved the Alamofire request inside of synchronous operation:

for jsonObject in jsonArray{
    queue.async {
    print("Started downloading " + filename)
    info.stringValue = "Downloading: " + filename
    info.placeholderString = "Downloading: " + filename
    info.isEnabled = true
    info.isHidden = false
    progress.isHidden = false
    let destination: DownloadRequest.DownloadFileDestination = { _, _ in
        let documentsURL = filepath
        return (documentsURL, [.removePreviousFile])
    }
    Alamofire.download(
        json["url"].stringValue,
        method: .get,
        to: destination).downloadProgress(closure: { (Alamoprogress) in
                info.stringValue = "Downloading: " + filename
            progress.doubleValue = Alamoprogress.fractionCompleted * 100
        }).response(completionHandler: { (DefaultDownloadResponse) in
                            })
           }
}

However, the debug log will continue to loop while downloading files and will download them asynchronously. This causes the info box and progress bar to go nuts while downloading, as it's downloading them all at once. I believe I have set up a synchronous loop however it may still be asynchronous in that is it looping through.

How can I prevent asynchronous downloads here?

1
There is no loop in the code you posted.rmaddy
@rmaddy I have updated it to include the loop, what I had before was just what was in the loop.Judge2020

1 Answers

7
votes

Use a semaphore so only one is downloading at a time:

let semaphore = DispatchSemaphore(value: 1)

for jsonObject in jsonArray {
    queue.async {
        semaphore.wait()

        print("Started downloading " + filename)
        info.stringValue = "Downloading: " + filename
        info.placeholderString = "Downloading: " + filename
        info.isEnabled = true
        info.isHidden = false
        progress.isHidden = false
        let destination: DownloadRequest.DownloadFileDestination = { _, _ in
            let documentsURL = filepath
            return (documentsURL, [.removePreviousFile])
        }
        Alamofire.download( json["url"].stringValue, method: .get, to: destination)
            .downloadProgress{ Alamoprogress in
                info.stringValue = "Downloading: " + filename
                progress.doubleValue = Alamoprogress.fractionCompleted * 100
            }
            .response { response in
                semaphore.signal()
            }
    }
}