【问题标题】:NSURLConnection sendAsynchronousRequest can't get variable out of closureNSURLConnection sendAsynchronousRequest 无法使变量脱离关闭状态
【发布时间】:2016-04-15 11:04:12
【问题描述】:

我正在尝试使用 POST 从 PHP 页面获取简单的文本响应。我有以下代码:

func post(url: String, info: String) -> String {
    var URL: NSURL = NSURL(string: url)!
    var request:NSMutableURLRequest = NSMutableURLRequest(URL:URL)
    var output = "Nothing Returned";
    request.HTTPMethod = "POST";
    var bodyData = info;
    request.HTTPBody = bodyData.dataUsingEncoding(NSUTF8StringEncoding);

    NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()){

        response, data, error in

        output = (NSString(data: data, encoding: NSUTF8StringEncoding))!


    }

    return output
}

虽然此代码不会引发任何错误,但当我这样调用它时:

println(post(url, info: data))

即使我要换行,它也只会打印:“Nothing Returned”:

output = (NSString(data: data, encoding: NSUTF8StringEncoding))!

到这里:

println((NSString(data: data, encoding: NSUTF8StringEncoding)))

它会打印出正确的响应。我在这里的变量做错了吗?

【问题讨论】:

  • sendAsynchronousRequest 是一个异步请求,因此您不会在块之后立即获得输出的值。你需要实现一个回调机制来处理它。

标签: ios post asynchronous swift nsurlconnection


【解决方案1】:

这是调用使用完成处理程序块/闭包的异步函数。因此,您需要在自己的代码中使用完成处理程序模式。这包括将方法返回类型更改为 Void 并添加一个新的 completionHandler 闭包,该闭包将在异步调用完成时被调用:

func post(url: String, info: String, completionHandler: (NSString?, NSError?) -> ()) {
    let URL = NSURL(string: url)!
    let request = NSMutableURLRequest(URL:URL)
    request.HTTPMethod = "POST"
    let bodyData = info
    request.HTTPBody = bodyData.dataUsingEncoding(NSUTF8StringEncoding);

    NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) { response, data, error in
        guard data != nil else {
            completionHandler(nil, error)
            return
        }

        completionHandler(NSString(data: data!, encoding: NSUTF8StringEncoding), nil)
    }
}

或者,由于NSURLConnection 现已正式弃用,使用NSURLSession 可能会更好:

func post(url: String, info: String, completionHandler: (NSString?, NSError?) -> ()) -> NSURLSessionTask {
    let URL = NSURL(string: url)!
    let request = NSMutableURLRequest(URL:URL)
    request.HTTPMethod = "POST"
    let bodyData = info
    request.HTTPBody = bodyData.dataUsingEncoding(NSUTF8StringEncoding);

    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { data, response, error in
        dispatch_async(dispatch_get_main_queue()) {
            guard data != nil else {
                completionHandler(nil, error)
                return
            }

            completionHandler(NSString(data: data!, encoding: NSUTF8StringEncoding), nil)
        }
    }
    task.resume()

    return task
}

你这样称呼它:

post(url, info: info) { responseString, error in
    guard responseString != nil else {
        print(error)
        return
    }

    // use responseString here
}

// but don't try to use response string here ... the above closure will be called
// asynchronously (i.e. later)

注意,为了简单起见,我使用了尾随闭包语法(请参阅 The Swift Programming Language: Closures尾随闭包 部分),但希望它能说明这个想法:你不能立即返回一个异步方法,因此提供一个完成处理程序闭包,该闭包将在异步方法完成时调用。

【讨论】:

  • 谢谢罗伯。我相信您已经回答了我的问题,但是您认为我应该使用 sendAsynchronousRequest 吗?我将它用于登录脚本,所以也许 sendSynchronousRequest 更好?
  • 你几乎从不想使用sendSynchronousRequest(你唯一会使用它的地方是后台线程,无论如何,它相对于主线程实际上是异步的)。像上面一样使用sendAsynchronousRequest,并将任何取决于成功登录的代码放入 post 调用的完成处理程序中。这是所有网络编程的核心:异步执行并将相关代码放入完成处理程序中。
  • 或者,正如在此答案的修订中指出的那样,您根本不应该使用 NSURLConnection,因为它现在已被弃用。你真的应该使用NSURLSession,它甚至不提供同步再现(这是一个很好的设计决策,恕我直言)。
猜你喜欢
  • 2014-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多