在 NSURLConnection 中的 Swift 中从 completionHandler 中获取数据

Posted

技术标签:

【中文标题】在 NSURLConnection 中的 Swift 中从 completionHandler 中获取数据【英文标题】:Getting data out of completionHandler in Swift in NSURLConnection 【发布时间】:2014-07-17 00:09:19 【问题描述】:

我正在尝试编写一个执行异步 GET 请求并返回响应的函数(作为任何数据类型,但这里是作为 NSData)。

本题基于:How to use NSURLConnection completionHandler with swift

func getAsynchData() -> NSData 
    var dataOutput : NSData
    let url:NSURL = NSURL(string:"some url")
    let request:NSURLRequest = NSURLRequest(URL:url)
    let queue:NSOperationQueue = NSOperationQueue()

    NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler: (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
            /* this next line gives the below error */
            dataOutput = data
    )
    return dataOutput

但我得到一个错误:

error: variable 'dataOutput' captured by a closure before being initialized

我已经尝试从completionHandler返回值,但它需要一个void返回,这让我想起了我希望在没有帮助的情况下解决这个问题......:D

我看过: How to use completionHandler Closure with return in Swift? 但这并不能真正回答我的问题。我的目标是从我的异步请求中获取数据,以便在我的代码中的其他地方使用。我是否应该在这个块中完成这个请求的所有工作,而不是把数据取出来?

谢谢!

编辑

好的,所以我有一个我认为可能可行的选项,但对我来说似乎不合适。谁能告诉我这是否是实现目标的最佳方式?

func doThingsWithData( data: NSData ) -> String 
    /* code to extract string from NSData */
    return somestring

func getAsynchData() 
    let url:NSURL = NSURL(string:"some url")
    let request:NSURLRequest = NSURLRequest(URL:url)
    let queue:NSOperationQueue = NSOperationQueue()

    NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler: (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
            /* this next line gives the below error */
            doThingsWithData(data)
    )

EDIT 2 -> 响应撤消

谢谢,撤消。你的回答对我来说很有意义。这里有更多的谜题。我有一个类是我的 API 处理程序。我希望能够实例化该类,并在其上调用一个函数以从 API 获取数据。我宁愿通过一个 api 调用获取所有数据,而不是每次为我需要输出的每个值都进行单独调用,因为单个 API 调用包含我需要的所有数据,但这可能是一个完全不同的答案。代码如下:

class GetInfoFromAPI 

    func getSpecificValue(index : String) -> String 
        /* I assume I need to send the values from this function, yea? but how do I get them here? */
    

    func doThingsWithData( data: NSData ) -> String 
        /* code to extract string from NSData */
        var error: NSError?
        let jsonDict = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &error) as NSDictionary

        specificValue1 : String = jsonDict.valueForKey("value1") as String
        specificValue2 : String = jsonDict.valueForKey("value2") as String
        specificValue3 : String = jsonDict.valueForKey("value3") as String

        /* I want to get these ^^^ values into the ViewController below */
    

    func getAsynchData() 
        let url:NSURL = NSURL(string:"some url")
        let request:NSURLRequest = NSURLRequest(URL:url)
        let queue:NSOperationQueue = NSOperationQueue()

        NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler: (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
            /* this next line gives the below error */
            doThingsWithData(data)
        )
    



class ViewController: UIViewController 

    @IBOutlet var labelVariable1: UILabel
    @IBOutlet var labelVariable2: UILabel
    @IBOutlet var labelVariable3: UILabel

    let apiInstance = GetInfoFromAPI()

    @IBAction func buttonTapped(sender : AnyObject) 
        labelVariable1 = apiInstance.getSpecificValue(1)
        labelVariable2 = apiInstance.getSpecificValue(2)
        labelVariable3 = apiInstance.getSpecificValue(3)
    


感谢您花时间回答我的问题。我是 swift 新手,堆栈溢出非常有用!

【问题讨论】:

var dataOutput: NSData! 怎么样? 当我使用var dataOutput: NSData! 时,我收到以下错误:fatal error: unexpectedly found nil while unwrapping an Optional value。我觉得这可能是因为它是一个异步请求,并且没有立即返回值。这让我相信我的第二次编辑可能是更好的选择 但很高兴知道!是否简单地隐式展开变量允许在嵌套函数中访问它?当我看到你的回复时,我捂住了脸:D 异步做事时,不能同步返回。所以你应该喜欢你的第二次编辑。使用 optional 可以让您跳过初始化,因为编译器将使用 nil 静默初始化。您可以初始化变量,而不是使用可选的,但在您的情况下,使用空数据进行初始化是浪费的。 【参考方案1】:

让我试着解释一下 - 这是对线程的误解,我自己一开始也很纠结。我将尝试简化一些事情。当您运行此代码时:

NSLog("Log 1")

NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler: (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
        NSLog("Log in Completion Block")
)

NSLog("Log after request")

您将获得如下所示的输出:

Log 1
Log after request
Log in completion block

让我做一个图表,有点像时间线:

                    "Log 1" (before request is sent)
                                       |
                                       |
                           Request sent over Internet
                                       |
                                     /   \  
                   "Log after request"   |
               This is logged *before*   | 
           the other one, because this   |
          one doesn't have to wait for   |
               the network to respond.   |
                                         |
The method finishes and returns a value. |
------------------------------------------------------------------------------
                                         | The network finally responds,
                                         | and the completion block is run.
                                         |

                                         "Log in completion block"

垂直线是方法结束和返回的地方。在所有情况下,您的方法在完成块运行之前已经向其调用者返回了一个值。你不能线性地考虑这个。

我是否应该在此块中处理此请求的所有工作,而不是取出数据?

是的,基本上。如果您首先向我展示调用 getAsynchData() 的代码,我可以提供更多帮助。

【讨论】:

谢谢撤消,这很有帮助。我在上面的主体中添加了更多代码,可以更全面地了解问题。 谢谢!我现在有点忙,我会试着在一两天内回到这个问题上。同时,我认为您需要研究委托和协议的概念。这应该会给你一个好的开始。 嘿撤消,你有机会再看看这个吗? @cosmikwolf 您能否提供有关您最终如何解决问题的最新信息?

以上是关于在 NSURLConnection 中的 Swift 中从 completionHandler 中获取数据的主要内容,如果未能解决你的问题,请参考以下文章

XCode 4.2.1 中的 NSURLConnection 文档在 iOS 上不存在吗?

iOS5 中的 NSURLConnection

何时取消 uinavigationcontroller 中的 nsurlconnection

iOS 中的 NSURLConnection 和基本 HTTP 身份验证

ios 9.2 中的 NSURLSession/NSURLConnection HTTP 加载失败 (kCFStreamErrorDomainSSL, -9802)

如何在情节提要中使用 NSURLConnection 下载文件