NSURLSessionUploadTask 获取响应数据

Posted

技术标签:

【中文标题】NSURLSessionUploadTask 获取响应数据【英文标题】:NSURLSessionUploadTask get response data 【发布时间】:2016-01-13 07:00:32 【问题描述】:

我在使用NSURLSession 框架时有一些误解,这就是为什么我决定不使用AFFramework/Alamofire 从头开始​​编写小应用程序。

我有一个 API 需要以下步骤来上传文件:

    POST 文件数据 获取响应 (JSON) 发布一些json字段到api/save

我有这样一个配置的后台会话:

let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("myBackground")
let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: nil)

我已经实现了两种方法:

func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData)

我在哪里汇总所有数据

func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?)

我将这些数据转换为响应对象。这个响应对象对我来说非常重要。

一切正常,而应用程序在前台,但我在后台遇到问题。

案例 1

应用程序在我开始上传数据后立即崩溃。根据 WWDC 我需要实施

func application(application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: () -> Void)

并在didCompleteWithError 方法中调用此处理程序。但在调用此方法之前,我需要使用上传响应中的数据调用api/save。 我怎样才能得到这些数据?

案例 2

大部分情况类似。用户在上传过程中停止应用程序。比在几秒钟内加载应用程序,而会话适用于我的任务。现在会话调用didReceiveData,但是当然,一些数据丢失了。在这种情况下我该怎么办?如何恢复响应数据?

【问题讨论】:

【参考方案1】:

您没有提到实现URLSessionDidFinishEventsForBackgroundURLSessionNSURLSessionDelegate 方法)。你真的很想实现它。基本流程是:

在应用代理的handleEventsForBackgroundURLSession 中,您应该:

启动后台NSURLSession(它将开始接收与所有上传相关的委托方法调用);和 保存完成处理程序(但暂时不要调用它)。

然后,在URLSessionDidFinishEventsForBackgroundURLSession(处理完所有响应后),调用保存在handleEventsForBackgroundURLSession 中的完成处理程序。 (确保将其分派到主队列。)

如果您正在执行所有这些操作,当后台会话重新启动时,didReceiveData 调用将与您的各种上传响应一起出现。

我刚刚做了一个快速测试,上传了 5 张 20mb 的图片并立即终止了应用程序。然后,即使应用程序没有运行,我也看到五个文件慢慢出现在我的服务器上(显然由守护进程处理)。当所有五个都完成后,应用程序在后台透明地重新启动,handleEventsForBackgroundURLSession 被调用(它重新启动了会话),它让所有didReceiveData 调用快速被调用,完成后,URLSessionDidFinishEventsForBackgroundURLSession被调用,然后我的应用程序才调用保存的完成处理程序。

就为什么这对您不起作用而言,不足以诊断问题。可能性包括:

您可能不恰当地终止了该应用程序。您不能通过双击主页按钮并在那里终止应用程序来终止应用程序;您必须让它自己自然终止,或者出于诊断/测试目的,我通过在代码中调用 exit(0) 来强制它终止。

可能在调用handleEventsForBackgroundURLSession 时您没有重新启动会话。

也许您调用提供的完成处理程序太快了(即在调用 URLSessionDidFinishEventsForBackgroundURLSession 之前)。

很难说,但我怀疑你的实现中隐藏着一些不太正确的东西,并且根据提供的信息很难说它是什么(假设它不是上述几点之一)。不幸的是,调试这个后台会话非常复杂,因为当应用程序终止时,它不再连接到调试器,所以你不能轻易调试应用程序被 ios 自动重启后发生的事情)。就个人而言,我要么NSLog 消息,然后只观察设备控制台(以及观察服务器上显示的内容),要么在应用程序本身中构建一些持久性日志记录机制。

【讨论】:

感谢您的精彩解释。我将您的答案标记为“正确”,因为(我相信)它将涵盖其他人的问题。但是,我已经实现了URLSessionDidFinishEventsForBackgroundURLSession,但没有运气。我重新启动了 bg 会话并得到了 URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) 我得到了以下数据:session: <__NSURLBackgroundSession: 0x1668c060> dataTask: <__NSCFBackgroundUploadTask: 0x165ade60> taskIdentifier: 1 data: 0 当我尝试附加数据时,我的应用程序崩溃了 如果你在某个地方(例如 GitHub 或其他)上传了一个工作演示,我很乐意看看。【参考方案2】:

为了测试后台会话代码,建议在真实设备上进行测试。在编写使用 NSURLSession 的后台会话支持的应用程序时,很容易被开发过程中的三个不明显的工件混淆:

当您从 Xcode 运行您的应用程序时,Xcode 会将该应用程序安装在一个新容器中,这意味着您的应用程序的路径会发生变化。这可能会混淆 NSURLSession 的后台会话支持。 注意:此问题已在 iOS 9 中修复;如果您在 iOS 9 或更高版本中遇到 NSURLSession 无法处理容器路径更改的问题,请提交错误。 Xcode 的调试可防止系统暂停您的应用。因此,如果您从 Xcode 运行您的应用,或者您在启动后的某个时间附加到该进程,然后将您的应用移至后台,您的应用将在系统会暂停它的情况下继续执行。 同样,iOS Simulator 无法准确模拟应用挂起和恢复;这在过去有效,但在 iOS 8 或 iOS 9 模拟器中不起作用。

来源:Apple Developer Forum

【讨论】:

以上是关于NSURLSessionUploadTask 获取响应数据的主要内容,如果未能解决你的问题,请参考以下文章

iOS NSURLSessionUploadTask 响应数据

NSURLSessionUploadTask 不上传带参数的图片

NSURLSessionUploadTask 在创建后直接取消[重复]

当应用程序挂起时,我如何知道 NSURLSessionUploadTask 是不是正在工作?

iOS开发之网络编程--5NSURLSessionUploadTask+NSURLSessionDataDelegate代理上传

我可以使用 NSURLSessionUploadTask 进行离线同步任务吗?