yageek
yageek

Reputation: 4455

Advanced NSOperations, callback for GroupOperation

I'm currently trying to use the concepts introduced during the WWDC about Advanced NSOperations. I would like to separate the process of making a request with different Operation subclasses (and by extension any kind of chained operations).

I use a context class to share data between all the operations involved in the process (See: Passing Data Between Two NSOperations)

class RequestContext {

    var httpResponse:NSHTTPURLResponse?
    var data:NSData?
    var JSON:AnyObject?
}

Each subclass get a reference to the context during initalization.

Example for download:

class DownloadOperation : GroupOperation {

    let requestContext:RequestContext


    init(context:RequestContext, apiCall:API){
        requestContext = context
        super.init(operations: [])
        name = "Generic Download"

        guard let URL = apiCall.URLRequest else {
            finish()
            return
        }

        let dataTask  = NSURLSession.sharedSession().dataTaskWithURL(URL) {
            data, response, error in

            self.downloadFinished(data, response: response as? NSHTTPURLResponse, error: error)
        }

        let downloadTask = URLSessionTaskOperation(task: dataTask)

        let reachabilityCondition = ReachabilityCondition(host: URL)

        let networkObserver = NetworkObserver()

        downloadTask.addCondition(reachabilityCondition)

        downloadTask.addObserver(networkObserver)

        addOperation(downloadTask)
    }


    private func downloadFinished(data:NSData?, response:NSHTTPURLResponse?, error:NSError?){
        if let data = data {
            requestContext.data = data
            requestContext.httpResponse = response
        } else {
            finishWithError(error)
        }
    }
}

Example JSON parsing:

class JSONUnmarshallOperation: Operation {

        let context:RequestContext

        init(context c:RequestContext){
            self.context = c

            super.init()

            name = "JSON Parsing"
        }

        final override func execute() {
            guard let data = context.data else { finish(); return }

            defer {
                context.data = nil
            }

            do {
                context.JSON = try NSJSONSerialization.JSONObjectWithData(data, options: [])
                finish()
            } catch let error as NSError {
                finishWithError(error)
            }

        }
    }

I would like to be able to create a GroupOperation that relies on this two operation and define a completion callback. I would like to have something like this:

 class SomeOperation: GroupOperation {

    let downloadOperation:DownloadOperation
    let unmarshalOperation:JSONUnmarshallOperation

    init (completionHandler:<* Some Type *>) {

        let blockOperation = NSBlockOperation {

            //Use the callback here and access self
        }


        super.init(operations:[downloadOperation, unmarshalOperation, blockOperation])
    }
}

The problem here, is that I would access to self before calling super.init

Is there a simple and elegant way to add a generic completion handler add the end of a GroupOperation subclass ?

Upvotes: 1

Views: 211

Answers (1)

Dave DeLong
Dave DeLong

Reputation: 243156

The simple answer is to not construct your blockOperation until after you've called super.init:

init (completionHandler:<* Some Type *>) {
    let downloadOperation = ...
    let unmarshallOperation = ...
    unmarshallOperation.addDependency(downloadOperation)

    super.init(operations:[downloadOperation, unmarshallOperation, blockOperation])

    let blockOperation = NSBlockOperation {
        //Use the callback here and access self
    }
    blockOperation.addDependency(unmarshallOperation)
    addOperation(blockOperation)
}

Upvotes: 3

Related Questions