4
votes

I have strange situation here. Assume you have task1 (NSURLSessionUploadTask) and it is uploading some huge data and user initiates task2 (NSURLSessionDataTask) which should not execute if task1 fails. On the other hand he might start another task3 which should run independently.

So my obvious choice was NSOperationQueue and dependency injection among the tasks.Here is my code.

import Foundation

class DependencyInjectorNSOperation : NSBlockOperation {
    var isSuccess : Bool = true
    var cleanUpCode : ((DependencyInjectorNSOperation) -> Void)? = nil

    override func cancel() {
        for operation in self.dependencies {
            operation.cancel()
        }
        isSuccess = false
        super.cancel()
    }

    override func start() {
        if cancelled == true {
            return
        }
        else if self.dependencies.count > 0 {
            for tasks in self.dependencies {
                if (tasks as! DependencyInjectorNSOperation).isSuccess != true{
                    cleanUpCode!(self)
                    return
                }
            }
             super.start()
        }
        else{
            super.start()
        }
    }
}

Now in NSOperation dependency will only take care of serialising the operations but will not cancel all the dependent operations if it fails. So I have added a property called isSuccess which I check in the start function. So when a task fails I set this property to false and when its dependent task starts I check whether all the dependent tasks finished successfully, if yes only then I continue the execution else close the NSOperation.

Each of this NSOperations starts a NSURLSessionTasks and runs it asynchronously. So if web request is successful I'll set the isSuccess to true or else I'll set it to false. And in order to do that I stop the NSOperation till NSURLSessionTasks results either in success or failure.

Issue

By the model I have used, if I have to make 30 web calls I'll be holding 30 NSOperations in NSOperationQueue and each will be blocking a thread while all its dependent operations wait in NSOperation Queue.

My Boss thinks its a very bad approach to introduce NSOperation for each task and add dependency among them and make NSOperation wait till web service returns either response or error.

If you think same as well then please suggest how can I achieve the serialisation among few web service calls using Alamofire or NSURLSession.

I thought of using PromiseKit for swift. Can anybody suggest will it work if NSURLSessionTasks starts asynchronously and it has to wait for some other task which is already in execution.

Thanks in advance.

1

1 Answers

2
votes

By the model I have used, if I have to make 30 web calls I'll be holding 30 NSOperations in NSOperationQueue and each will be blocking a thread while all its dependent operations wait in NSOperation Queue.

This isn't true. An Operation is not assigned to a thread until it is started, and it won't start as long as its dependencies aren't complete. Managing task dependencies is exactly what OperationQueue is for.

I probably wouldn't quite code it the way you have (mostly minor things around the use of ! and I'd probably use !cancelled rather than isSuccess), but your basic approach is almost precisely the one presented by Apple in Advanced NSOperations. If you're going to go this way, I suggest studying Apple's Earthquakes code which even includes an URLSessionTaskOperation precisely for this purpose.