最近,我试图写自己的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以获取数据的方法的kicks
getMe()移动到下一行执行并返回一个字符串(此时仍然为空)。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数据返回之前返回结果。但这种方法可能会使您的主线程停滞,而且不太可能是正确的选择。

09-03 21:32