从URLSession获取接收数据的方法是什么?

时间:2016-08-18 13:49:56

标签: swift macos swift3

最近,我试图写自己的Telegram Bot API。但是,这个项目似乎已经在URLSession(以前称为NSURLSession)问题上遇到了障碍。

呼叫结构如下:

getMe() -> getData() -> NSURLSession

理想情况下,我希望将NSURLSession返回的数据传回getMe()以供应用程序处理。但是,我尝试过的方法无法证明这一点。

以下是我一直在使用的代码。 synthesiseURL()生成应用程序应打开会话的URL,以便在Telegram Bot API上执行操作。 synthesiseURL()生成的网址模板为https://api.telegram.org/bot\(token)/\(tgMethod)

// NSURLSession getData: gets data from Telegram Bot API
func getData(tgMethod: String, arguments: [String] = [String](), caller: String = #function) {
    let url = synthesiseURL(tgMethod: "getMe"), request = NSMutableURLRequest(url: url)

    var receivedData = String()

    let session = URLSession.shared.dataTask(with: request as URLRequest) { data, response, err in

        if err != nil {print(err!.localizedDescription); return}

        DispatchQueue.main.async {
            receivedData = String(data: data!, encoding: String.Encoding.nonLossyASCII)!
            print(receivedData)
        }
    }

    session.resume()
}

我一直试图让getData将包含Bot API响应的receivedData传递回函数getMe

func getMe() -> String {
    HTTPInterface(botToken: token).get(tgMethod: "getMe")
    return [???] // here's where the data from getData() should come
}

我已尝试完成处理程序,回调,对主线程的异步调用等,但似乎没有按预期工作(getMe()返回空字符串)。

为什么会如此,是否可以修复?

1 个答案:

答案 0 :(得分:1)

基本问题是您的getMe()函数被声明为具有立即String返回类型,但它取决于获取该字符串的延迟/异步调用。时间表看起来像这样:

  1. getMe()由某些客户端代码调用
  2. getMe()启动URLSession获取数据的方法
  3. getMe()移动到下一行执行并返回一个字符串(此时仍为空)。现在已返回getMe()函数,并且客户端代码执行继续向前,空String结果
  4. URLSession完成数据,但执行已经移动,因此数据无法在任何地方使用
  5. 最简单的解决方法是让你的getMe函数没有返回类型,但是当URLSession数据返回时也要回调一个closure参数,例如:

    func getMe(callback:String->()) {
         //getData and pass a closure that executes the callback closure with the String data that comes back
    }
    

    不太容易解决的问题是使用像调度信号量这样的技术来阻止getMe()返回结果,直到URLSession数据返回。但是这种方法可能会阻碍你的主线程,并且不太可能是正确的选择。