Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing result of NSOperation to another NSOperation

I have two NSOperation that are responsible for Downloading, and Parsing. After the downloading operation is successful and I receive some NSData I want to then set that data as the data to be used by the parsing operation:

init(context: NSManagedObjectContext, completionHandler: Void -> Void) {

    downloadOperation = DownloadActivitiesOperation() { data in
        self.parseOperation.data = data
    }
    parseOperation = ParseActivitiesOperation(context: context)

    let finishOperation = NSBlockOperation(block: completionHandler)

    parseOperation.addDependency(downloadOperation)
    finishOperation.addDependency(parseOperation)

    super.init(operations: [downloadOperation, parseOperation, finishOperation])

    name = "Get Activities"
}

This however doesn't work as I'm attempting to use self inside of my download completion block before calling super.init.

My question is what would be the best approach when attempting to pass the result of one operation to the next one in the chain?

like image 348
Kyle Decot Avatar asked Sep 09 '25 19:09

Kyle Decot


2 Answers

Each instance of NSOperation contains array of dependencies. Operations are not removed from this array after finishing. You can use those objects to access the data:

class DownloadActivitiesOperation: NSOperation {
   var data: NSData?
   ...
   // set self.data when it has downloaded
}

class ParseActivitiesOperation: NSOperation {
    func main() {
      if let downloadOp = self.dependencies.last as? DownloadActivitiesOperation {
          let dataToParse = downloadOp.data
          ...
      }
    }
 }

And so on.

like image 160
Ilia Avatar answered Sep 12 '25 11:09

Ilia


Use a file cache

It looks like you are using some kind of implementation of GroupOperation from the WWDC2015 talk on Advanced NSOperations. In the sample code from the talk they use a cache file to pass data between the downloader and the parser.

Following snippet from the GetEarthquakesOperation class:

    
        let cachesFolder = try! NSFileManager.defaultManager().URLForDirectory(.CachesDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)

        let cacheFile = cachesFolder.URLByAppendingPathComponent("earthquakes.json")
        
        /*
            This operation is made of three child operations:
            1. The operation to download the JSON feed
            2. The operation to parse the JSON feed and insert the elements into the Core Data store
            3. The operation to invoke the completion handler
        */
        downloadOperation = DownloadEarthquakesOperation(cacheFile: cacheFile)
        parseOperation = ParseEarthquakesOperation(cacheFile: cacheFile, context: context)

Use a memory cache

My current solution in one of my projects is to wrap the results in a class and pass it to both operations:


class OperationResultWrapper<T> {
    var result: T?
}


    let wrapper = OperationResultWrapper<NSData>()
    downloadOperation = DownloadEarthquakesOperation(resultWrapper: wrapper)
    parseOperation = ParseEarthquakesOperation(dataWrapper: wrapper, context: context)

like image 28
tidbeck Avatar answered Sep 12 '25 11:09

tidbeck