How to use completionHandler Closure with return in Swift?

I am trying to us a RESTful API that returns some json data. I want to encapsulate the code that creates the HTTP Request and sets the headers in its own method so I can call it by entering a url String and then have the method return a JSON object.

In the following snippet of code, I have already created the request object and set the headers, and I call that variable “req”. I have not declared any objects named data, response, or error. I have the following code that correctly prints out a JSON object

  • Completely unrelated error using coredata
  • Difference between using Generic and Protocol as type parameters, what are the pros and cons of implement them in a function
  • How to import own classes from your own project into a Playground
  • Passing an implicitly unwrapped variable into inout parameter doesn't compile
  • Using stringByReplacingCharactersInRange in Swift
  • Navigation bar disappears if reload data with UISearchController
  • let sesh = NSURLSession.sharedSession()
        let dataTask = sesh.dataTaskWithRequest(req, completionHandler: {(data, response, error) in
            var jsonError : NSError?
            let jsonBlob = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableLeaves, error: &jsonError)
            println(jsonBlob)
            });
    
        dataTask.resume()
    

    So here’s my question. How do I make it so that this completionHandler block is able to return the jsonBlob, which is of type “AnyObject!”? If I modify the code slightly to be the following:

    let sesh = NSURLSession.sharedSession()
        let dataTask = sesh.dataTaskWithRequest(req, completionHandler: {(data, response, error) -> AnyObject! in
            var jsonError : NSError?
            let jsonBlob : AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableLeaves, error: &jsonError)
            return jsonBlob
            });
    
        dataTask.resume()
    

    then the program will not compile as the call to dataTaskWithRequest:completionHandler gives a compiler warning saying:

     Could not find an overload for 'dataTaskWithRequest' that accepts the supplied arguments
    

    I don’t understand this. I’m using the correct syntax for returning closures, as is given in this page of the Swift Docs:

    https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html

    4 Solutions Collect From Internet About “How to use completionHandler Closure with return in Swift?”

    func getSomething(callback: (Array<AnyObject>) -> ()) {
        var dataTask = NSURLSessionDataTask()
        dataTask = session.dataTaskWithRequest(request) { (data, response, error) in
            if (error == nil) {
                var callbackArray = Array<MyObject>()
                let responseDict = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: nil) as NSDictionary
                let response = responseDict.objectForKey("response_key") as NSDictionary
                let array = response.objectForKey("array_key") as NSArray
    
                for item: AnyObject in array {
                    var arrayItem = MyObject(dict: item as NSDictionary)
                    callbackArray.append(arrayItem)
                }
    
                callback(callbackArray)
            } else {
                // handle an error
            }
        }
        dataTask.resume()
    }
    

    Then you could do something like:

    getSomething() { (response) in
        if let responseArray = response as? Array<MyObject> {
            self.somethings = responseArray
        }
    }
    

    as you see here, the dataTaskWithRequest:completionHandler: has a completion handler with no expected return value.

    completion handler's interface

    that means the NSURLSession instance do not expect any value from you to proceed after calling this method; with other words: you completion closure (or block, if you like) ends the procedure here.

    there is not clear why you’d like sending back anything to the caller via the completion handler.

    The completion handler can’t return anything because the closure you have to supply has to be of return type Void and not AnyObject!.

    func dataTaskWithRequest(_ request: NSURLRequest!,
       completionHandler completionHandler: ((NSData!,
                                  NSURLResponse!,
                                  NSError!) -> Void)!) -> NSURLSessionDataTask!
    

    I came across a similar issue when trying to update info in a central DB based on content was pulling from CloudKit. The patterns for pulling CK data all have these asynchronous completion handlers which allow no return value.

    Since I wanted to be able to re-use similar code in different contexts, I separated the CK calls out into their own class and defined a delegate protocol that I made the core class conform to. Within the completion handlers I sent data retrieved from the CK calls back to where I want them stored via delegate methods.

    Easy peasy.