NSURLSession的下载和断点继传以及后台下载功能
来源:互联网 发布:使用excel制作软件 编辑:程序博客网 时间:2024/05/19 12:25
一.大体步骤
NSURLSession始于ios7.它具有访问接口,上传/下载数据,断点继传和后台下载等功能: 其使用步骤:
1. 创建session指定其configuration 2. 由session执行任务得到task 3. task调用resume,启动网络请求
二.task分类
session的任务有四种:
1. 数据任务 Data task 2. 下载任务 Download task 3. 上传任务 Upload task 4. 流任务 Stream task ios9之后出现的,用于TCP/IP流
三. configuration类型
configuration的类型有三种:
1. 默认配置 Default sessions: 使用磁盘缓存,用将证书存在用户的钥匙串 2. 及时配置 Ephemeral sessions: 不使用磁盘缓存,也存储证书,它的信息存于RAM中,如果session被invalidate,这些信息也被清理掉 3. 后台配置 Background sessions: 配置上同默认配置,但是有一个独立进程来操作上传/下载
四.session生成task方式
对于生成每种task的方法,共有4种方式,举downloadTask为例子
1.用urlrequest请求
public func downloadTaskWithRequest(request: NSURLRequest) -> NSURLSessionDownloadTask
2.用url请求
public func downloadTaskWithURL(url: NSURL) -> NSURLSessionDownloadTask
3.带handler的URLRequest请求,注意,如果写了handler,就不会进入代理方法,即使设置了代理也没用
public func downloadTaskWithRequest(request: NSURLRequest, completionHandler: (NSURL?, NSURLResponse?, NSError?) -> Void) -> NSURLSessionDownloadTask
4.带handler的URL请求
public func downloadTaskWithURL(url: NSURL, completionHandler: (NSURL?, NSURLResponse?, NSError?) -> Void) -> NSURLSessionDownloadTask
五.task分类讲解
下面讲解每种task的具体使用方法
NSURLSession的代理继承关系如图:
NSURLSessionDelegate
|
NSURLSessionTaskDelegate
| | |
NSURLSessionDataDelegate NSURLSessionDownloadDelegate NSURLSessionStreamDelegate
1. 数据任务 Data task
使用:
let config = NSURLSessionConfiguration.defaultSessionConfiguration()let url = NSURL(string:datadUrlNeighbor)task.resume()
进入代理方法顺序:
1.首先进入NSURLSessionDataDelegate的didReceiveResponse方法.我们要手动在这里调用completionHandler(.Allow).系统才会继续进入下一步的代理方法,否则到此就结束了
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) {//这个方法,只有在session的task是datatask的时候才会进入 completionHandler(.Allow)}
2.然后进入didReceiveData方法,获得json数据,可以做业务操作
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) { print("did receive data") let dic = try? NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers) print("get dic:\(dic!)")}
3.然后进入didCompleteWithError方法,它是NSURLSessionTaskDelegate的方法,表示请求结束了
func URLSession(session: NSURLSession, task: NSURLSessionTask, error: NSError?) { print("did complete")}
2. 下载任务 Download task
使用:
let config = NSURLSessionConfiguration.defaultSessionConfiguration()let session = NSURLSession(configuration: config,delegate: self, delegateQueue: NSOperationQueue.mainQueue())//方式一 :不使用handler 会进入代理方法let url = NSURL(string:datadUrlNeighbor)let downloadTask = session.downloadTaskWithURL(url!)downloadTask.resume()
进入代理方法顺序:
1.NSURLSessionDownloadDelegate的didWriteData,数据正在写入沙盒的tmp文件夹,就会调用这个方法.它是分批次写入的,每写入一段数据就调用这个方法一次,所以会被多次调用
参数解释:bytesWritten是本次写入的数据长度totalBytesWritten是已经写在磁盘上的长度totalBytesExpectedToWrite是数据本来的长度
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { print("didwrite:\(bytesWritten), \(totalBytesWritten), \(totalBytesWritten), \(totalBytesExpectedToWrite)")}
2.NSURLSessionDownloadDelegate的didFinishDownloadingToURL方法,当数据下载完成后,此时的文件是一个以tmp结尾的文件,命名类似于:
3.进入这个方法didFinishDownloadingToURL.在这里必须执对tmp文件的转移处理,否则当除了这个方法后,tmp文件就被删除了.
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) { print("download to url:\(location)") self.moveToCache(location, name: "ivy.zip") self.tintLabel.text = "download to url"}
4.进入didCompleteWithError方法
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?){}
三. 上传
由于上传本人研究不深入,暂时不写,以后更新本节
四. 断点继传
使用:
注意:1. 这里和下载的区别是:task设置为成员变量了,因为在中断的时候,需要这个task来调用cancelByProducingResumeData2. session也设置为了成员变量,因为在继传的时候,需要用这个session来调用downloadTaskWithResumeData,开启一个新的downloadtask
//经测试这里写backgroundconfig和defaultconfig都可以//let config = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(backgroundId)let config = NSURLSessionConfiguration.defaultSessionConfiguration()downloadSession = NSURLSession(configuration: config,delegate: self, delegateQueue: NSOperationQueue.mainQueue())let url = NSURL(string:downloadUrlNeighbor)downloadSessionTask = downloadSession!.downloadTaskWithURL(url!)downloadSessionTask!.resume()
顺序:
1. 按下中止按钮:
在回调块中,保存 self.resumeData,便于在继传时使用
downloadSessionTask?.cancelByProducingResumeData({ (data:NSData?) in self.resumeData = data self.downloadSessionTask = nil //downloadSessionTask已经没用了 要置为nil,因为下次继传时会由session新开一个task})
如果不按下中止按钮,它进入代理方法的顺序和正常下载是完全一样的.即先进入didWriteData,然后进入didFinishDownloadingToURL,最后didCompleteWithError
如果按下中止按钮,会发生:
1. 进入didWriteData,毕竟也是写了一些数据的2. 会进cancelByProducingResumeData的回调,在回调里,我们要记录下resumedata,这是继传时要传入的参数,还要设置成员downloadSessionTask为nil,因为下次的继传会由session创建一个新的task,通过调用downloadTaskWithResumeData3. 进入代理didCompleteWithError方法
2. 继传
比如我们用一个按钮来启动继传,其中的代码如下:
就是保存的成员变量task 调用downloadTaskWithResumeData方法
@IBAction func clickGoOn(sender: AnyObject) { guard self.resumeData != nil else{ return } //这样写可以进入代理:1 didFinishDownloadingToURL 2 didCompleteWithError downloadSessionTask = downloadSession?.downloadTaskWithResumeData(self.resumeData!) downloadSessionTask?.resume()}
由于downloadTaskWithResumeData也有2种方式,带handler和不带handler的,如果调用了带有handler的那个,则不进入代理方法
进入代理方法的顺序:
1.didResumeAtOffset
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64) { print("didresume:\(fileOffset),total:\(expectedTotalBytes)")}
2.didWriteData 又开始写入磁盘了
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { print("didwrite:\(bytesWritten), \(totalBytesWritten), \(totalBytesExpectedToWrite)")}
3.didFinishDownloadingToURL 这个比较重要,一次下载可以多次中止,但是只有全部写入成功后才会进入这个代理, 在这里将 下载的文件转移走,不然出了这个方法会被删除的
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) { print("download to url:\(location)") self.resumeUrl = location self.moveToCache(self.resumeUrl, name: "ivy.zip") self.tintLabel.text = "download to url" }
4.didCompleteWithError 这回是真的下载完成了
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?){ print("did complete")}
四. 后台下载
在下载过程中,如果按home键将app切换到后台,只要不杀死程序,session还能保持其下载能力,完成后,通知到appdelegate的handleEventsForBackgroundURLSession方法.
.虽然app不会因此回到前端
注意: 1. 后台config必须使用backgroundSessionConfigurationWithIdentifier,要传入一个唯一的标识符 2. 有几个下载任务就要创建几个config和session.每个任务都需要一个独立标示的config,以及session 3. session必须设置delegate 4. 只支持HTTP/HTTPS模式 5. 只支持从文件上传,不支持从data上传(也就是只能用这个函数:func uploadTaskWithRequest(request: NSURLRequest, fromFile fileURL: NSURL, completionHandler: (NSData?, NSURLResponse?, NSError?) -> Void) -> NSURLSessionUploadTask 而不能用这个函数:func uploadTaskWithRequest(request: NSURLRequest, fromFile fileURL: NSURL, completionHandler: (NSData?, NSURLResponse?, NSError?) -> Void) -> NSURLSessionUploadTask) 6. 请用真机调试,模拟器按下home键之后不会有效果,而是会一直在delegate里下载直到完成为止
使用:
let config = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(backgroundId)let session = NSURLSession(configuration:config, delegate:self, delegateQueue: NSOperationQueue.mainQueue())let url = NSURL(string:downloadUrlNeighbor)let task = session.downloadTaskWithURL(url!)task.resume()
进入代理顺序:
1.开始下载时
NSURLSessionDownloadDelegate代理的didWriteData方法
2.按下home,APP进入后台
代理的didWriteData方法不再被进入,而是程序后台静默下载
3.下载完成后
第一步:进入AppDelegate的方法:
func application(application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: () -> Void) { //self.downloadCompletionHandler = completionHandler print("----application hadle event") let config = NSURLSessionConfiguration.backgroundSessionConfiguration(identifier) //The new session is automatically reassociated with ongoing background activity. //这个session被自动绑定到了后台运行的app let session = NSURLSession(configuration: config , delegate:self.mySessionDelegate, delegateQueue:NSOperationQueue.mainQueue()) //去使用的类里面注册一个handler, 直接传过去也可以的,其实self.window.rootViewController = xxx也可以的 self.mySessionDelegate.addCompletionHandler(completionHandler, identifier: identifier)}
解释: 1. 保存handler的方式是多种的, 可以给AppDelegate设置一个dictionary的属性.也可以传入session的delegate的dictionary属性,我选择了后者 2. 要创建一个session,文档说这个session会被自动绑定到后台的activity
第二步:
进入NSURLSessionDownloadDelegate的didFinishDownloadingToURL方法,请在这里 搬运下载好的tmp文件
第三步:进入didCompleteWithError
第四步:进入NSURLSessionDelegate的URLSessionDidFinishEventsForBackgroundURLSession方法
func URLSessionDidFinishEventsForBackgroundURLSession(session: NSURLSession){ print("did finish events") if (session.configuration.identifier != nil) { let handler = self.completionHandlerDictionary![session.configuration.identifier!] guard handler != nil else { return} handler!() //移除 dictionary中的数据 self.completionHandlerDictionary?.removeValueForKey(session.configuration.identifier!) self.tintLabel.text = "finish event" }}
在第三步或第四步里面, 把从appdelegate里面获取到的handler执行一下,这么做的目的,文档告诉我们是为了让操作系统知道程序可以被继续安全的挂起.
参考文档:
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/URLLoadingSystem/Articles/UsingNSURLSession.html#//apple_ref/doc/uid/TP40013509-SW44
demo: https://github.com/ivychenyucong/TestNSURLSession
ps:打算翻译下那篇参考文档 含金量挺高的
- NSURLSession的下载和断点继传以及后台下载功能
- C# FTP下载的断点继传
- NSURLSession前台下载/后台下载/断点下载的代理执行路径(一)
- NSURLSession前台下载/后台下载/断点下载的代理执行路径(二)
- NSURLSession实现断点下载
- 【iOS】NSURLSession断点下载
- NSURLSession实现断点下载
- NSURLSession 断点下载
- iOS NSURLSession后台下载和断点续传
- iOS使用NSURLSession进行下载(包括后台下载,断点下载)
- iOS开发-使用NSURLSession实现文件断点下载,文件离线续传以及图片上传
- NSURLSession的上传和下载
- NSURLSession NSURLConnection下载大文件 断点下载
- NSURLSession下载的断点续传以及实…
- iOS后台下载、断点下载
- 断点后台下载
- NSURLSession 简单入门及断点下载续传实例
- iOS关于使用NSURLSession进行大文件下载以及断点下载
- Java环境搭建(JDK+MyEclipse+Maven+Resin)
- android 6.0 优先网络类型设置流程(Preferrred network type)
- error: ‘PATH_MAX’ undeclared (first use in this function)
- c#中将json数据转换为dictionary并取出某个元素显示
- Redis学习笔记(九)redis 配置文件详解
- NSURLSession的下载和断点继传以及后台下载功能
- 夜半游白岛心安随笔记
- dfs
- win7下的ie11开发者工具报错
- webstrom 2016.1 破解链接
- NSIS FQA
- MongoDB 命令笔记
- ARM、X86/Atom、MIPS、PowerPC
- Extjs 解决表单提交总是执行failure回调函数