最近,我试图写自己的Telegram Bot API。然而,该项目似乎遇到了URLSession(以前的NSURLSession)问题。
调用结构如下:getMe() -> getData() -> NSURLSession
理想情况下,我希望将从NSURLSession
返回的数据传递回getMe()
以便应用程序进行处理。然而,我尝试过的方法并没有证明这是可能的。
下面是我一直在使用的代码。synthesiseURL()
生成应用程序应打开会话以对Telegram Bot API执行操作的URL。synthesiseURL()
生成的URL模板是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()
返回空字符串)。为什么会这样,它能被修复吗?
最佳答案
最基本的问题是,getMe()
函数被声明为具有immediateString
返回类型,但它依赖于延迟/异步调用来获取该字符串。时间线如下所示:getMe()
由某些客户端代码调用getMe()
启动URLSession
以获取数据的方法的kicksgetMe()
移动到下一行执行并返回一个字符串(此时仍然为空)。getMe()
函数现在已返回,客户端代码的执行继续向前推进,结果为空String
以数据完成,但执行已经继续,因此数据不会在任何地方使用
最简单的解决方法是使URLSession
函数没有返回类型,但是在URLSession数据返回时也会回调闭包参数,如下所示:
func getMe(callback:String->()) {
//getData and pass a closure that executes the callback closure with the String data that comes back
}
较不容易的解决方法是使用诸如分派信号量之类的技术来防止
getMe
在URLSession数据返回之前返回结果。但这种方法可能会使您的主线程停滞,而且不太可能是正确的选择。