我在使用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)
并在CCD_ 3方法中调用该处理程序。但在调用此方法之前,我需要使用上传响应中的数据调用api/save
。如何获取这些数据?
情况2
大多数情况类似。用户在上传过程中停止应用程序。Than在几秒钟内加载应用程序,而会话处理我的任务。现在会话调用didReceiveData
,但当然,有些数据丢失了。在这种情况下我该怎么办?如何恢复响应数据?
您没有提到实现URLSessionDidFinishEventsForBackgroundURLSession
(NSURLSessionDelegate
方法)。你真的也想实现这一点。基本流程是:
-
应用程序内代理的
handleEventsForBackgroundURLSession
,您应该:- 启动后台
NSURLSession
(它将开始接收与所有上传相关联的委托方法调用);以及 - 保存完成处理程序(但不要调用它)
- 启动后台
-
然后,在
URLSessionDidFinishEventsForBackgroundURLSession
中(处理完所有响应后),调用保存在handleEventsForBackgroundURLSession
中的完成处理程序。(确保将其发送到主队列。)
如果您正在执行所有这些操作,当后台会话重新启动时,didReceiveData
调用将对您的各种上传做出响应。
我只是做了一个快速测试,上传了五张20mb的图片,并立即终止了应用程序。然后,即使应用程序没有运行,我也看到这五个文件慢慢出现在我的服务器上(显然是由守护进程处理的)。当这五个都完成后,by应用程序在后台透明地重新启动,handleEventsForBackgroundURLSession
被调用(它重新启动了会话),它让所有didReceiveData
调用快速被调用,当这一切完成后,URLSessionDidFinishEventsForBackgroundURLSession
被调用,我的应用程序只调用了保存的完成处理程序。
就为什么这对你不起作用而言,没有足够的信息来诊断问题。可能性包括:
-
也许您不恰当地终止了应用程序。你不能通过双击主页按钮并在那里终止应用程序来杀死应用程序;您必须让它自己自然地终止,或者出于诊断/测试目的,我通过在代码中调用
exit(0)
来强制它终止。 -
也许您在调用
handleEventsForBackgroundURLSession
时没有重新启动会话。 -
可能您调用所提供的完成处理程序过快(即在调用
URLSessionDidFinishEventsForBackgroundURLSession
之前)。
这很难说,但我怀疑您的实现中隐藏着一些不太正确的东西,而且很难根据提供的信息(假设它不是上述要点之一)说出它是什么。不幸的是,调试这个后台会话非常复杂,因为当应用程序终止时,它不再连接到调试器,因此您无法轻松调试iOS自动重启应用程序后发生的事情)。就我个人而言,我要么NSLog
消息,只看设备控制台(以及服务器上出现的内容),要么在应用程序本身中构建一些持久的日志记录机制。
对于测试后台会话代码,建议在真实设备上进行测试。当编写一个使用NSURLSession后台会话支持的应用程序时,很容易被开发过程中的三个不明显的工件所混淆:
- 当您从Xcode运行应用程序时,Xcode会将应用程序安装在一个新容器中,这意味着应用程序的路径会更改。这可能会混淆NSURLSession的后台会话支持。注意:此问题已在iOS 9中修复;如果您在iOS 9或更高版本中遇到NSURLSession无法处理容器路径更改的问题,请提交一个错误
- Xcode的调试可防止系统挂起您的应用程序。因此,如果你从Xcode运行你的应用程序,或者在启动后一段时间连接到进程,然后将应用程序移到后台,那么在系统本来会暂停的情况下,你的应用将继续执行
- 同样,iOS模拟器也不能准确模拟应用程序暂停和恢复;这在过去是有效的,但在iOS 8或iOS 9模拟器中不起作用
来源:苹果开发者论坛