NSURLSessionUploadTask 获取响应数据
NSURLSessionUploadTask get response data
我在使用 NSURLSession
框架时有一些误解,这就是为什么我决定在没有 AFFramework/Alamofire 的情况下从头开始编写小应用程序的原因。
我有一个 API 需要按照以下步骤上传文件:
- POST 文件数据
- 获取响应(JSON)
- Post 一些 json 字段到
api/save
我有一个这样配置的后台会话:
let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("myBackground")
let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: nil)
我已经实现了 2 种方法:
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData)
我汇总所有数据的地方
和
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?)
我在哪里将此数据转换为响应对象。这个响应对象如果对我来说非常重要。
一切正常,应用程序在前台,但我在后台遇到问题。
案例一
应用程序在我开始上传数据后立即崩溃。根据 WWDC,我需要实施
func application(application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: () -> Void)
并在 didCompleteWithError
方法中调用此处理程序。但在调用此方法之前,我需要使用上传响应中的数据调用 api/save
。
我怎样才能得到这些数据?
案例二
大部分情况相似。用户在上传过程中停止应用程序。比在几秒钟内加载应用程序,而会话与我的任务一起工作。现在会话调用 didReceiveData
,但当然会丢失一些数据。遇到这种情况怎么办?如何恢复响应数据?
您没有提到实施 URLSessionDidFinishEventsForBackgroundURLSession
(NSURLSessionDelegate
方法)。你也真的想实现它。基本流程是:
在应用委托的 handleEventsForBackgroundURLSession
中,您应该:
- 启动后台
NSURLSession
(它将开始接收与所有上传相关联的委托方法调用);和
- 保存完成处理程序(但不要调用它)。
然后,在 URLSessionDidFinishEventsForBackgroundURLSession
中(处理完所有响应后),调用保存在 handleEventsForBackgroundURLSession
中的完成处理程序。 (确保将其分派到主队列。)
如果您执行所有这些操作,当后台会话重新启动时,didReceiveData
调用将随您的各种上传响应一起进入。
我刚刚做了一个快速测试,上传了五张 20mb 的图片并立即终止了应用程序。然后,即使该应用程序不是 运行,我也看到这五个文件慢慢出现在我的服务器上(显然由守护进程处理)。当所有五个都完成后,应用程序在后台透明地重新启动,调用 handleEventsForBackgroundURLSession
(重新启动会话),它让所有 didReceiveData
调用快速被调用,当它完成时,URLSessionDidFinishEventsForBackgroundURLSession
被调用,然后我的应用才调用保存的完成处理程序。
就为什么这对您不起作用而言,还不足以诊断问题。可能性包括:
可能您不恰当地终止了该应用程序。您不能通过双击主页按钮并在那里终止应用程序来终止应用程序;你必须让它自己自然终止,或者出于 diagnostic/testing 目的,我通过在代码中调用 exit(0)
强制它终止。
可能调用 handleEventsForBackgroundURLSession
时您没有重新启动会话。
也许您调用提供的完成处理程序的时间过早(即在调用 URLSessionDidFinishEventsForBackgroundURLSession
之前)。
很难说,但我怀疑您的实现中隐藏了一些不太正确的东西,并且很难根据所提供的信息说出它是什么(假设它不是其中之一)以上几点)。不幸的是,调试这个后台会话非常复杂,因为当应用程序终止时,它不再附加到调试器,因此您无法轻松调试应用程序自动重启后发生的事情 iOS)。就个人而言,我要么 NSLog
消息并只观察设备控制台(以及观察服务器上出现的内容),要么我在应用程序本身中构建一些持久的日志记录机制。
为了测试后台会话代码,建议在真实设备上进行测试。在编写使用 NSURLSession 的后台会话支持的应用程序时,很容易被开发过程中的三个不明显的工件搞糊涂:
- 当您 运行 来自 Xcode 的应用时,Xcode 会在新容器中安装该应用,这意味着您的应用路径会发生变化。这可能会混淆 NSURLSession 的后台会话支持。
注意:此问题已在 iOS 9 中修复;如果您在 iOS 9 或更高版本中遇到 NSURLSession 无法处理容器路径更改的问题,请提交错误。
- Xcode 的调试可防止系统挂起您的应用程序。因此,如果您 运行 您的应用程序来自 Xcode,或者您在启动后的某个时间附加到该进程,然后将您的应用程序移至后台,您的应用程序将继续执行,否则系统将无法运行已暂停。
- 同样,iOS 模拟器不能准确模拟应用挂起和恢复;这在过去有效,但在 iOS 8 或 iOS 9 模拟器中不起作用。
我在使用 NSURLSession
框架时有一些误解,这就是为什么我决定在没有 AFFramework/Alamofire 的情况下从头开始编写小应用程序的原因。
我有一个 API 需要按照以下步骤上传文件:
- POST 文件数据
- 获取响应(JSON)
- Post 一些 json 字段到
api/save
我有一个这样配置的后台会话:
let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("myBackground")
let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: nil)
我已经实现了 2 种方法:
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData)
我汇总所有数据的地方
和
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?)
我在哪里将此数据转换为响应对象。这个响应对象如果对我来说非常重要。
一切正常,应用程序在前台,但我在后台遇到问题。
案例一
应用程序在我开始上传数据后立即崩溃。根据 WWDC,我需要实施
func application(application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: () -> Void)
并在 didCompleteWithError
方法中调用此处理程序。但在调用此方法之前,我需要使用上传响应中的数据调用 api/save
。
我怎样才能得到这些数据?
案例二
大部分情况相似。用户在上传过程中停止应用程序。比在几秒钟内加载应用程序,而会话与我的任务一起工作。现在会话调用 didReceiveData
,但当然会丢失一些数据。遇到这种情况怎么办?如何恢复响应数据?
您没有提到实施 URLSessionDidFinishEventsForBackgroundURLSession
(NSURLSessionDelegate
方法)。你也真的想实现它。基本流程是:
在应用委托的
handleEventsForBackgroundURLSession
中,您应该:- 启动后台
NSURLSession
(它将开始接收与所有上传相关联的委托方法调用);和 - 保存完成处理程序(但不要调用它)。
- 启动后台
然后,在
URLSessionDidFinishEventsForBackgroundURLSession
中(处理完所有响应后),调用保存在handleEventsForBackgroundURLSession
中的完成处理程序。 (确保将其分派到主队列。)
如果您执行所有这些操作,当后台会话重新启动时,didReceiveData
调用将随您的各种上传响应一起进入。
我刚刚做了一个快速测试,上传了五张 20mb 的图片并立即终止了应用程序。然后,即使该应用程序不是 运行,我也看到这五个文件慢慢出现在我的服务器上(显然由守护进程处理)。当所有五个都完成后,应用程序在后台透明地重新启动,调用 handleEventsForBackgroundURLSession
(重新启动会话),它让所有 didReceiveData
调用快速被调用,当它完成时,URLSessionDidFinishEventsForBackgroundURLSession
被调用,然后我的应用才调用保存的完成处理程序。
就为什么这对您不起作用而言,还不足以诊断问题。可能性包括:
可能您不恰当地终止了该应用程序。您不能通过双击主页按钮并在那里终止应用程序来终止应用程序;你必须让它自己自然终止,或者出于 diagnostic/testing 目的,我通过在代码中调用
exit(0)
强制它终止。可能调用
handleEventsForBackgroundURLSession
时您没有重新启动会话。也许您调用提供的完成处理程序的时间过早(即在调用
URLSessionDidFinishEventsForBackgroundURLSession
之前)。
很难说,但我怀疑您的实现中隐藏了一些不太正确的东西,并且很难根据所提供的信息说出它是什么(假设它不是其中之一)以上几点)。不幸的是,调试这个后台会话非常复杂,因为当应用程序终止时,它不再附加到调试器,因此您无法轻松调试应用程序自动重启后发生的事情 iOS)。就个人而言,我要么 NSLog
消息并只观察设备控制台(以及观察服务器上出现的内容),要么我在应用程序本身中构建一些持久的日志记录机制。
为了测试后台会话代码,建议在真实设备上进行测试。在编写使用 NSURLSession 的后台会话支持的应用程序时,很容易被开发过程中的三个不明显的工件搞糊涂:
- 当您 运行 来自 Xcode 的应用时,Xcode 会在新容器中安装该应用,这意味着您的应用路径会发生变化。这可能会混淆 NSURLSession 的后台会话支持。 注意:此问题已在 iOS 9 中修复;如果您在 iOS 9 或更高版本中遇到 NSURLSession 无法处理容器路径更改的问题,请提交错误。
- Xcode 的调试可防止系统挂起您的应用程序。因此,如果您 运行 您的应用程序来自 Xcode,或者您在启动后的某个时间附加到该进程,然后将您的应用程序移至后台,您的应用程序将继续执行,否则系统将无法运行已暂停。
- 同样,iOS 模拟器不能准确模拟应用挂起和恢复;这在过去有效,但在 iOS 8 或 iOS 9 模拟器中不起作用。