【问题标题】:What is the way to get received data out of URLSession?从 URLSession 中获取接收数据的方法是什么?
【发布时间】:2016-08-18 13:49:55
【问题描述】:

最近,我尝试编写自己的Telegram Bot API。但是,该项目似乎遇到了 URLSession(以前的 NSURLSession)问题。

调用结构如下:

getMe() -> getData() -> NSURLSession

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

以下是我一直在使用的代码。 synthesiseURL() 生成应用程序应打开会话的 URL,以便对 Telegram Bot API 执行操作。 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() 返回一个空字符串)。

为什么会这样,能解决吗?

【问题讨论】:

    标签: swift macos swift3


    【解决方案1】:

    基本问题是您的getMe() 函数被声明为具有立即的String 返回类型,但它依赖于延迟/异步调用来获取该字符串。时间线如下所示:

    1. getMe() 被一些客户端代码调用
    2. getMe() 启动 URLSession 以获取数据的方法
    3. getMe() 移动到下一行执行并返回一个字符串(此时仍为空)。 getMe() 函数现已返回,客户端代码继续执行,结果为空的 String
    4. URLSession 已完成数据,但已继续执行,因此数据不会在任何地方使用

    最简单的解决方法是让您的 getMe 函数没有返回类型,但在 URLSession 数据返回时也回调闭包参数,例如:

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

    不太容易的解决方法是使用诸如分派信号量之类的技术来防止getMe() 在 URLSession 数据返回之前返回结果。但是这种方法很可能会使您的主线程停滞,并且不太可能是正确的选择。

    【讨论】:

    • 感谢您的回答!关于您建议的关闭,我应该如何获取这些数据并在主线程上处理它?是否可以将数据传递给getMe() 以供getMe() 用作返回值?
    • @perhapsmaybeharry 您可以在getMe() 函数中使用诸如调度信号量之类的东西来强制执行暂停,直到getMe() 从URLSession 获得答案,然后将该答案用作返回值。但是,这可能会阻塞主线程并冻结 UI,直到响应返回(坏主意)。最好的方法是让任何调用getMe() 的代码传入一个闭包,当getMe() 最终异步完成时,该闭包应该与字符串结果一起执行,而不是期望从getMe() 函数立即返回。
    • 我明白了。从这个意义上说,我想我会使用异步完成处理程序。感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多