SimplGy
SimplGy

Reputation: 20437

Pass scope to a named function, rather than a closure

I would like to separate the data processing of my NSURLSession into a separate method.

When making a URL request, I rely on the enclosing scope to provide me the user's callback.

This works:

static func makeRequest(url: String, callback: APICallback) {
  let urlObject = NSURL(string: url)
  var request = createRequest(urlObject!, method: "GET") // internal
  var session = NSURLSession.sharedSession()
  var task = session.dataTaskWithRequest(request){
      (data, response, error) -> Void in

    // do some basic parsing, error checking, then...
    callback(data, nil)

  }
  task.resume()
}

There's rather a lot of basic parsing and error checking I'd like to do at the application level, however, so I want to define and pass a function instead of a closure to the dataTaskWithRequest method:

static func makeRequest(url: String, callback: APICallback) {
  let urlObject = NSURL(string: url)
  var request = createRequest(urlObject!, method: "GET") // internal
  var session = NSURLSession.sharedSession()
  var task = session.dataTaskWithRequest(request, completionHandler: gotResponse)
  task.resume()
}


static private func gotResponse (nsdata: NSData!, response: NSURLResponse!, err: NSError!) -> Void {

  // Do my parsing and handling here, instead.
  // OOPS! Don't have access to the callback. :(
}

This all leads me to my question, which, despite the lengthy example, is about language features. Can I pass some captured scope to this method? In Javascript I could accomplish this using Function.prototype.bind, but I'm not sure how to do it in Swift.

Upvotes: 1

Views: 113

Answers (1)

Airspeed Velocity
Airspeed Velocity

Reputation: 40963

This seems like a good example of when to use a curried method. Declare the function like this with a first parameter of an APICallback. Note the brackets.

static private func gotResponse(callback: APICallback)(nsdata: NSData!, response: NSURLResponse!, err: NSError!) -> Void {

    // use callback: like normal
}

Then, use it like this:

var task = session.dataTaskWithRequest(request, completionHandler: gotResponse(callback))

(apologies, the syntax might not be 100% correct since your code isn’t stand alone so I can’t test it fully)

Curried functions are a little finicky and had some bugs in 1.1 (though they got fixed in 1.2), so instead of using the language support for them, you could try hand-rolling if the above doesn’t work, something like:

static private func gotResponse(callback: APICallback) -> (nsdata: NSData!, response: NSURLResponse!, err: NSError!) -> Void {

    return { data, response, error in
        // put the common code, capturing callback:, in here...

    }
}

Upvotes: 2

Related Questions