Reputation: 4455
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
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