在Swift中,当使用dataTaskWithRequest时,completionHandler在请求超时时返回一个nil NSURLResponse

时间:2015-02-17 19:24:11

标签: ios swift

当我将数据发布到服务时,请求通常很好,但是如果它需要太长时间并且超时,则在完成处理程序中,我将NSURLResponse设置为nil,即使它永远不会返回nil。

我正在使用Swift 1.1,这是我如何做到这一点的一个例子:

func postX(actionKey:String, postData:AnyObject, callBack:((data:NSData?, resp: NSURLResponse) -> Void)?) -> Void
{
    var mreq = createRequest(actionKey, method: "POST", https: true, json: true)
    if (self.dataTask != nil)
    {
        self.dataTask?.cancel()
    }
    var err: NSError?
    mreq.HTTPBody = NSJSONSerialization.dataWithJSONObject(postData, options: nil, error: &err)
    self.dataTask = self.getSession().dataTaskWithRequest(mreq, completionHandler: { (data:NSData!, resp: NSURLResponse!, error: NSError!) -> Void in

        Dlog.log("response: \(resp)")  //Prints out: response: nil
        if (error != nil)
        {
            //do something
        }
        else
        {
            //do something else
        }
    })
    if (self.dataTask != nil)
    {
        self.dataTask!.resume()
    }
}

1 个答案:

答案 0 :(得分:3)

NSURLResponse completionHandler块中的dataTaskWithRequest引用是可选的(意味着它可以nil)。如果请求超时,您希望它是nil(因为您可能尚未收到任何回复)。

我建议您将NSURLResponse闭包的callback参数更改为可选,就像dataTaskWithRequest一样。 (我也可能会返回可选的NSError,因此您可以检查特定错误。)并且您可以通过查找NSURLErrorTimedOut来检测超时错误。

例如:

func postX(actionKey: String, postData: AnyObject, callBack: (NSData?, NSURLResponse?, NSError?) -> ()) {
    let request = createRequest(actionKey, method: "POST", https: true, json: true)

    dataTask?.cancel()   // note, we don't need `if` clause, as the `?` does everything for us

    request.HTTPBody = try! NSJSONSerialization.dataWithJSONObject(postData, options: [])

    let task = getSession().dataTaskWithRequest(request) { data, response, error in
        callBack(data, response, error)
    }

    task.resume()

    dataTask = task
}

然后你就可以使用它:

postX(actionKey, postData: postData) { data, response, error in

    // handle response however you want

    // did it time out?

    if error?.domain == NSURLErrorDomain && error?.code == NSURLErrorTimedOut {
        print("timed out") // note, `response` is likely `nil` if it timed out
    }

}

为了完整起见,Swift 3实现可能如下所示:

func postX(actionKey: String, postData: AnyObject, callBack: (Data?, URLResponse?, NSError?) -> ()) {
    var request = createRequest(actionKey: actionKey, method: "POST", https: true, json: true)

    dataTask?.cancel()   // note, we don't need `if` clause, as the `?` does everything for us

    request.httpBody = try! JSONSerialization.data(withJSONObject: postData, options: [])

    let task = getSession().dataTask(with: request) { data, response, error in
        callBack(data, response, error)
    }

    task.resume()

    dataTask = task
}

func createRequest(actionKey: String, method: String, https: Bool, json: Bool) -> URLRequest {
    var request = URLRequest(url: ...)
    ...
    return request
}

它会被称为:

postX(actionKey: actionKey, postData: postData) { data, response, error in

    // handle response however you want

    // did it time out?

    if error?.domain == NSURLErrorDomain && error?.code == NSURLErrorTimedOut {
        print("timed out") // note, `response` is likely `nil` if it timed out
    }

}