最近,我试图写自己的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()
返回空字符串)。
为什么会如此,是否可以修复?
答案 0 :(得分:1)
基本问题是您的getMe()
函数被声明为具有立即String
返回类型,但它取决于获取该字符串的延迟/异步调用。时间表看起来像这样:
getMe()
由某些客户端代码调用getMe()
启动URLSession
获取数据的方法getMe()
移动到下一行执行并返回一个字符串(此时仍为空)。现在已返回getMe()
函数,并且客户端代码执行继续向前,空String
结果URLSession
完成数据,但执行已经移动,因此数据无法在任何地方使用最简单的解决方法是让你的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数据返回。但是这种方法可能会阻碍你的主线程,并且不太可能是正确的选择。