修复 NSURLConnection 弃用从 Swift 1.2 到 2.0

Fixing NSURLConnection Deprecation from Swift 1.2 to 2.0

我有一个用 Swift 1.2 编写的函数,用于检查地址或 IP 的可达性。在这里:

func isHostConnected(hostAddress : String) -> Bool
{
    var response : NSURLResponse?
    let request = NSMutableURLRequest(URL: NSURL(string: hostAddress)!)
    request.timeoutInterval = 3

    let data = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: nil)

    return ((response as? NSHTTPURLResponse)!.statusCode == 200)
}

现在,NSURLConnection 已弃用,根据 Xcode 的建议,我尝试使用 NSURLSession.dataTaskWithRequest 编写它,这里是:

func isHostConnected(hostAddress : String) -> Bool
{
    let request = NSMutableURLRequest(URL: NSURL(string: hostAddress.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!)!)
    request.timeoutInterval = 3

    let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(), delegate: nil, delegateQueue: NSOperationQueue.mainQueue())

    var responseCode = -1

    session.dataTaskWithRequest(request, completionHandler: {(data : NSData?, response : NSURLResponse?, error : NSError?) -> Void in
        responseCode = (response as? NSHTTPURLResponse)!.statusCode
    })!.resume()

    return (responseCode == 200)
}

上面的代码总是 returns false(很明显),因为 completionHandler 在单独的线程上执行。

我担心的是,我能否像 sendSynchronousRequest 那样通过阻止它在 MainThread 上创建 completionHandler() 运行。

我有理由不在这里使用“Apple 的可达性”。

任何建议都会有所帮助。 :)

(重复我在 中的论点:)

Checking if a resource exists on a server requires sending a HTTP request and receiving the response. TCP communication can take some amount of time, e.g. if the server is busy, some router between the client and the server does not work correctly, the network is down etc.

That's why asynchronous requests are always preferred. Even if you think that the request should take only milliseconds, it might sometimes be seconds due to some network problems. And – as we all know – blocking the main thread for some seconds is a big no-no.

也就是说,您可以使用 "counting semaphore" 或 "dispatch group" 来等待某个异步任务的完成。 你应该在主线程上使用它。阻塞主线程 最多 3 秒是不可接受的!

func isHostConnected(hostAddress : String) -> Bool
{
    let request = NSMutableURLRequest(URL: NSURL(string: hostAddress.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!)!)
    request.timeoutInterval = 3
    request.HTTPMethod = "HEAD"

    let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
    var responseCode = -1

    let group = dispatch_group_create()
    dispatch_group_enter(group)

    session.dataTaskWithRequest(request, completionHandler: {(_, response, _) in
        if let httpResponse = response as? NSHTTPURLResponse {
            responseCode = httpResponse.statusCode
        }
        dispatch_group_leave(group)
    })!.resume()

    dispatch_group_wait(group, DISPATCH_TIME_FOREVER)
    return (responseCode == 200)
}

备注:

  • 将 HTTP 方法设置为 "HEAD" 是一个小的优化,因为 服务器只发送没有实际数据的响应头。
  • 在非法主机名的情况下,response 将是 nil,并且 responseCode = (response as? NSHTTPURLResponse)!.statusCode 会崩溃。