Execute swift nsurlsession Tasks in serial order

453 Views Asked by At

I don’t know how to execute multiple NSUrlSession tasks one by one. When first task finishes start second task, when second task finishes start third task etc

For example I want to download multiple files from a web service.

I want them to begin downloading one by one.

For example files: 1.png , 2.png , 3.png

I want them to be downloaded in the same order I wrote them.

How can I do that with NSUrlSession?

1

There are 1 best solutions below

0
Rob On

A couple of things:

  1. Traditional iOS solution is to wrap the network request task in an asynchronous Operation subclass (e.g., such as outlined in point 3 of this answer; see this answer for another permutation of that base AsynchronousOperation). Just set the queue’s maxConcurrentOperationCount to 1 and you have serial/sequential download of images.

  2. But you really don’t want to do that because you pay huge performance penalty by downloading images sequentially. The only time you should perform network requests sequentially is if you absolutely need the response of one request in the preparation of the next request (e.g. a “login request” retrieves a token and a subsequent request that uses the token for authentication purposes).

    But when dealing with a series of images, though, it’s going to be much faster to download the images concurrently. Store them in a dictionary (or whatever) as they come in:

    var imageDictionary: [URL: UIImage] = [:]
    

    Then:

    imageDictionary[url] = image
    

    Then, when you want the images in order of your original array of URLs, you just lookup the image associated with a URL, for example:

    let sortedImages = urls.compactMap { imageDictionary[$0] }
    
  3. Alternatively, you might completely rethink the notion of downloading a series of images up-front. For example, if these are image view’s in a table view, you might just use a third party library, such as Kingfisher, and use its UIImageView method setImage(with:):

    let url = URL(string: "https://example.com/image.png")
    imageView.kf.setImage(with: url)
    

    This gets you completely out of the business of fetching images and managing caches, low memory warnings, etc. This just-in-time pattern can result in more performant user interfaces. And even if you really want to download them in advance (a bit of an edge case, so make sure you really need to do that), libraries like Kingfisher can manage that too.