如何在Swift中使用completionHandler Closure返回?

时间:2014-07-09 07:12:55

标签: swift closures

我正在尝试使用RESTful API来返回一些json数据。我想封装创建HTTP请求的代码并在其自己的方法中设置标头,以便我可以通过输入url String来调用它,然后让方法返回一个JSON对象。

在下面的代码片段中,我已经创建了请求对象并设置了标题,我将该变量称为“req”。我没有声明任何名为data,response或error的对象。我有以下代码正确打印出一个JSON对象

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()

所以这是我的问题。如何使这个completionHandler块能够返回类型为“AnyObject!”的jsonBlob?如果我稍微修改代码如下:

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()

然后程序将不会编译为对dataTaskWithRequest的调用:completionHandler给出编译器警告说:

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

我不明白这一点。我正在使用正确的语法来返回闭包,如Swift Docs的这一页所示:

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

4 个答案:

答案 0 :(得分:34)

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()
}

然后你可以这样做:

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

答案 1 :(得分:4)

如您所见heredataTaskWithRequest:completionHandler:有一个没有预期回报值的完成处理程序。

completion handler's interface

这意味着NSURLSession实例在调用此方法后不希望任何值 来自 继续;换句话说:你完成闭包(或阻止,如果你愿意)在这里结束程序。

不清楚为什么要通过完成处理程序向调用者发回任何内容。

答案 2 :(得分:2)

完成处理程序不能返回任何内容,因为你必须提供的闭包必须是返回类型Void而不是AnyObject!。

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

答案 3 :(得分:0)

在尝试根据CloudKit提取的内容更新中央数据库中的信息时,我遇到了类似的问题。用于提取CK数据的模式都具有这些异步完成处理程序,这些处理程序不允许返回值。

由于我希望能够在不同的上下文中重用相似的代码,我将CK调用分离到它们自己的类中,并定义了一个我使核心类符合的委托协议。在完成处理程序中,我将从CK调用中检索到的数据发送回我希望它们通过委托方法存储的位置。

轻松自负。