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】:您没有提到实现URLSessionDidFinishEventsForBackgroundURLSession
(NSURLSessionDelegate
方法)。你真的很想实现它。基本流程是:
在应用代理的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代理上传