Advanced NSOperations: NSURLSessionDataTask vs NSURLSessionDownloadTask

I recently posted a question on StackOverflow... Chaining Multiple Async Functions in Swift

This eventually lead me to watching the excellent session from WWDC 2015... Advanced NSOperations

I have previously used NSOperation and NSOperationQueue but never in a way as powerful as they demonstrated in this session.

So, I thought my problems were solved! I downloaded the sample code that came along with the session and started putting it into my own project.

... And then something very odd started happening. I was using NSURLSessionDataTask where the sample code was using NSURLSessionDownloadTask but I thought nothing of it. Until I started getting race conditions in my code that meant I couldn't rely on the order of things happening. This was causing inconsistencies in my project and incorrect data being interpreted.

I then went back to the sample code to try and break it in the same way.

It eventually lead to this quick playground code to test what was going on...

Playground.gist

When I ran this with the download task the output was as follows...

download started
download finished
completion handler started
completion handler finished
task set to .Completed

And then when run with the data task the output was...

download started
download finished
completion handler started
task set to .Completed
completion handler finished

As you can see from this, the download task wait for its completion handler to finish before completing itself. However, the data task has a built in race condition with its own completion handler?! WHAT?!

I don't know why this is (yet) but I'm trying to look into it and possibly find a way around it.

Anyway, if you're having problems with NSURLSessionDataTask then maybe this is a good place to start.

This inconsistency just baffles me. Just another inconsistency to challenge us.

The search continues...

One Comment

  1. indiekiduk

    The reason is the download and the completion are on different threads. The completion is actually done on the delegateQueue param to an NSURLSession, and if nil is supplied then a default NSOperationQueue with max simultaneous operations set to 1 is used. This queue is completely independent on the internal queue processing network requests. This has a benefit that if a completion is taking too long it doesn't affect the speed of the next download. Since you cannot rely on the order of the completion handlers it has the unfortunate limitation you cannot pass the result of one task into the next. Be wary of that sample code, the developer is not as much of an expert in networking and UI as he is in operations.

Leave a Reply

Your email address will not be published. Required fields are marked *