Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alamofire: How to download files sequentially

I have an array of video files that I want to download. I am using a for loop to download each of them. However when the loop runs, all the files download in parallel, which causes the app to hang, the UI to freeze, CPU use to go through the roof.

for url in urlArray{
  downloadfile(url)
}

I have a function that downloads the file given a URL.

func downloadFile(s3Url:String)->Void{ 
    Alamofire.download(.GET, s3Url, destination: destination)
         .progress { bytesRead, totalBytesRead, totalBytesExpectedToRead in
             println(totalBytesRead)
         }
         .response { request, response, _, error in
             println(response)
         }
}

How can I change this so the files dont all download at the sametime? Also, how can I check that a download is finished so I can update my UI?

like image 353
CraigH Avatar asked Aug 24 '15 23:08

CraigH


3 Answers

func downloadFile(var urlArray:[String])->Void{
    if let s3Url = urlArray.popLast(){
        Alamofire.download(.GET, s3Url, destination: destination)
            .progress { bytesRead, totalBytesRead, totalBytesExpectedToRead in
                println(totalBytesRead)
            }
            .response { request, response, _, error in
                downloadFile(urlArray)
                println(response)
        }
    }
}

swift 3.0:

func downloadFile(urlArray:[String])->Void{
    var urlArray = urlArray
    if let s3Url = urlArray.popLast(){
        Alamofire.download(.GET, s3Url, destination: destination)
            .progress { bytesRead, totalBytesRead, totalBytesExpectedToRead in
                println(totalBytesRead)
            }
            .response { request, response, _, error in
                downloadFile(urlArray)
                println(response)
        }
    }
}
like image 110
LK Yeung Avatar answered Nov 17 '22 14:11

LK Yeung


What you could do is call out to another function when a file completes downloading (i.e. totalBytesRead >= totalBytesExpectedToRead). In that function, pop the next item off your list and call the download function again with the new URL. You could make an array of all the URLs and when you need a new item, remove it from the array and pass it to the download function. Check if the array is empty and if it is, you know you are done downloading everything.

The reason you can't just use a loop as you have is that Alamofire requests are always asynchronous so after the request is made, control returns immediately and your program continues before any data is downloaded.

like image 6
Ben Stahl Avatar answered Nov 17 '22 14:11

Ben Stahl


I hope this will help.

var urlArray:[String] =["your file link","your file link"] 

func downloadFile(url: String)->Void{

        let destination = DownloadRequest.suggestedDownloadDestination(for: .documentDirectory)

        Alamofire.download(
            url,
            method: .get,
            encoding: JSONEncoding.default,
            to: destination).downloadProgress(closure: { (progress) in
                //progress closure

            }).response(completionHandler: { (DefaultDownloadResponse) in
                //here you able to access the DefaultDownloadResponse
                //result closure
                self.urlArray.removeFirst()
                if DefaultDownloadResponse.response?.statusCode == 200 {

                    print(DefaultDownloadResponse.destinationURL)

                    if !self.urlArray.isEmpty{
                            self.downloadFile(url: self.urlArray[0])
                    }
                }

            })
}
like image 2
Fırat Yenidünya Avatar answered Nov 17 '22 13:11

Fırat Yenidünya