NSURLSession 简介
NSURLConnection这个名字,实际上指的是一组构成Foundation框架中URL加载系统的相互关联的组件:NSURLRequest,NSURLResponse,NSURLProtocol,NSURLCache,NSHTTPCookieStorage,NSURLCredentialStorage,以及和它同名的NSURLConnection。
在WWDC 2013中,Apple的团队对NSURLConnection进行了重构,并推出了NSURLSession作为替代。
NSURLSession也是一组相互依赖的类,它的大部分组件和NSURLConnection中的组件相同如NSURLRequest,NSURLCache等。而NSURLSession的不同之处在于,它将NSURLConnection替换为NSURLSession和NSURLSessionConfiguration,以及3个NSURLSessionTask的子类:NSURLSessionDataTask, NSURLSessionUploadTask, 和NSURLSessionDownloadTask。
NSURLSession 支持 task 特性,NSURLSessionConfiguration 配置对象,以及代理之外还提供了很多关于网络请求的相关特性,比如缓存控制,Cookie 控制,HTTP 验证操作等等。总之 NSURLSession 简单的接口之外,也提供了强大的体系。
获取NSURLSession类对象有几种方式:
/* * The shared session uses the currently set global NSURLCache, * NSHTTPCookieStorage and NSURLCredentialStorage objects. */ + (NSURLSession *)sharedSession; /* * Customization of NSURLSession occurs during creation of a new session. * If you only need to use the convenience routines with custom * configuration options it is not necessary to specify a delegate. * If you do specify a delegate, the delegate will be retained until after * the delegate has been sent the URLSession:didBecomeInvalidWithError: message. */ + (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration; + (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(id <NSURLSessionDelegate>)delegate delegateQueue:(NSOperationQueue *)queue;
第一种方式是使用静态的sharedSession方法,该类使用共享的会话,该会话使用全局的Cache,Cookie和证书。这个实例是全局共享的,并且功能受限。比如,由于全局实例没有代理对象,我们就不能够检测诸如下载进度这类的事件。以及我们无法设置后台下载的机制,等等。
第二种方式是通过sessionWithConfiguration:方法创建对象,也就是创建对应配置的会话,与NSURLSessionConfiguration合作使用。系统默认创建一个新的OperationQueue处理Session的消息
第三种方式是通过sessionWithConfiguration:delegate:delegateQueue方法创建对象,二三两种方式可以创建一个新会话并定制其会话类型。该方式中指定了session的委托和委托所处的队列。当不再需要连接时,可以调用Session的invalidateAndCancel直接关闭,或者调用finishTasksAndInvalidate等待当前Task结束后关闭。这时Delegate会收到URLSession:didBecomeInvalidWithError:这个事件。Delegate收到这个事件之后会被解引用。(-finishTasksAndInvalidate and -invalidateAndCancel do not have any effect on the shared session singleton.)
获取NSURLSessionConfiguration类
其中NSURLSessionConfiguration用于配置会话的属性,可以通过该类配置会话的工作模式:
+ (NSURLSessionConfiguration *)defaultSessionConfiguration; //这个配置会使用全局的缓存,cookie 等信息,这个相当于 NSURLSessionConfiguration 的默认配置行为。
+ (NSURLSessionConfiguration *)ephemeralSessionConfiguration; //这个配置不会对缓存或 cookie 以及认证信息进行存储,相当于一个私有的 Session,如果你开发一个浏览器产品,这个配置就相当于浏览器的隐私模式。
+ (NSURLSessionConfiguration *)backgroundSessionConfiguration:(NSString *)identifier; //这个配置可以让你的网络操作在你的应用切换到后台的时候还能继续工作,identifier参数指定了会话的ID,用于标记后台的session。
除了这三种预设的模式之外 NSURLSessionConfiguration 还可以进行很多的配置。NSURLSessionConfiguration中的属性:
timeoutIntervalForRequest 和 timeoutIntervalForResource 可以控制网络操作的超时时间。
allowsCellularAccess 性指定是否允许使用蜂窝连接。
HTTPAdditionalHeaders 可以指定 HTTP 请求头。
discretionary属性为YES时表示当程序在后台运作时由系统自己选择最佳的网络连接配置,该属性可以节省通过蜂窝连接的带宽。在使用后台传输数据的时候,建议使用discretionary属性,而不是allowsCellularAccess属性,因为它会把WiFi和电源可用性考虑在内。补充:这个标志允许系统为分配任务进行性能优化。这意味着只有当设备有足够电量时,设备才通过Wifi进行数据传输。如果电量低,或者只仅有一个蜂窝连接,传输任务是不会运行的。后台传输总是在discretionary模式下运行。
NSURLSessionConfiguration 几乎可以完成网络操作的大多数配置功能,并且这些配置都绑定到当前的 Session 中,我们一旦用配置好的 NSURLSessionConfiguration 初始化 NSURLSession 实例后,就不能修改这个 NSURLSession 相关的配置了。所以,一切的配置操作都放在初始化 NSURLSession 之前。
NSURLSessionTask类
NSURLSession 本身是不会进行请求的,而是通过创建 task 的形式进行网络请求(resume() 方法的调用),同一个 NSURLSession 可以创建多个 task,并且这些 task 之间的 cache 和 cookie 是共享的。那么我们就来看看 NSURLSession 都能创建哪些 task 吧。
NSURLSessionTask是一个抽象子类,它有三个子类:NSURLSessionDataTask,NSURLSessionUploadTask和NSURLSessionDownloadTask。这三个类封装了现代应用程序的三个基本网络任务:获取数据,比如JSON或XML,以及上传和下载文件。
下面是其继承关系:
NSURLSessionDataTask: 这个就是我们第一个例子中创建的 DataTask,它主要用于读取服务端的简单数据,比如 JSON 数据。
NSURLSessionDownloadTask: 这个 task 的主要用途是进行文件下载,它针对大文件的网络请求做了更多的处理,比如下载进度,断点续传等等。
NSURLSessionUploadTask: 和下载任务对应,这个 task 主要是用于对服务端发送文件类型的数据使用的。
看几个例子,比如如何下载文件:
let imageURL = NSURL(string: "https://httpbin.org/image/png")! NSURLSession.sharedSession().downloadTaskWithURL(imageURL) { location, response, error in guard let url = location else { return } guard let imageData = NSData(contentsOfURL: url) else { return } guard let image = UIImage(data: imageData) else { return } dispatch_async(dispatch_get_main_queue()) { //... } }.resume()
下载文件的时候,我们使用 downloadTaskWithURL 方法,这个方法的闭包中会接受一个 location 参数,这个参数表示我们下载好的文件的存放位置。
注意,downloadTaskWithURL 会将文件保存在一个临时目录中,location 参数指向这个临时目录的位置,如果我们要将下载好的文件进行持久保存的话,我们还需要将文件从这个临时目录中移动出来。
我们通过 location 参数可以找到文件的位置,然后将文件的内容读取出来,就像我们上面的例子中那样。
有多种方法创建对应的任务对象:
(1)NSURLSessionDataTask
通过request对象或url创建:
/* Creates a data task with the given request. The request may have a body stream. */ - (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request; /* Creates a data task to retrieve the contents of the given URL. */ - (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url;
通过request对象或url创建,同时指定任务完成后通过completionHandler指定回调的代码块:
/* * data task convenience methods. These methods create tasks that * bypass the normal delegate calls for response and data delivery, * and provide a simple cancelable asynchronous interface to receiving * data. Errors will be returned in the NSURLErrorDomain, * see <Foundation/NSURLError.h>. The delegate, if any, will still be * called for authentication challenges. */ - (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler; - (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler;
(2)NSURLSessionUploadTask
通过request创建,在上传时指定文件源或数据源。
/* Creates an upload task with the given request. The body of the request will be created from the file referenced by fileURL */ - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL; /* Creates an upload task with the given request. The body of the request is provided from the bodyData. */ - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(NSData *)bodyData; /* Creates an upload task with the given request. The previously set body stream of the request (if any) is ignored and the URLSession:task:needNewBodyStream: delegate will be called when the body payload is required. */ - (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request;
在创建upload task对象时,通过completionHandler指定任务完成后的回调代码块:
/* * upload convenience method. */ - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler; - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromData:(NSData *)bodyData completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler;(3)NSURLSessionDownloadTask
/* Creates a download task with the given request. */ - (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request; /* Creates a download task to download the contents of the given URL. */ - (NSURLSessionDownloadTask *)downloadTaskWithURL:(NSURL *)url; /* Creates a download task with the resume data. If the download cannot be successfully resumed, URLSession:task:didCompleteWithError: will be called. */ - (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData;
下载任务支持断点续传,第三种方式是通过之前已经下载的数据来创建下载任务。
同样地可以通过completionHandler指定任务完成后的回调代码块:
/* * download task convenience methods. When a download successfully * completes, the NSURL will point to a file that must be read or * copied during the invocation of the completion routine. The file * will be removed automatically. */ - (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURL *location, NSURLResponse *response, NSError *error))completionHandler; - (NSURLSessionDownloadTask *)downloadTaskWithURL:(NSURL *)url completionHandler:(void (^)(NSURL *location, NSURLResponse *response, NSError *error))completionHandler; - (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData completionHandler:(void (^)(NSURL *location, NSURLResponse *response, NSError *error))completionHandler;
NSURLSessionDelegate的介绍
我们前面的例子都是通过一个闭包在网络操作完成的时候进行处理。那么有什么方法可以监听网络操作过程中发生的事件呢,比如我们下载一个大文件的时候,如果要等到下载完成可能会需要比较长的事件,这时候更好的体验是能够提供一个下载进度。类似这样的事件我们就需要用到代理。
我们在使用三种 task 的任意一种的时候都可以指定相应的代理。NSURLSession 的代理对象结构如下:
NSURLSessionDelegate - 作为所有代理的基类,定义了网络请求最基础的代理方法。
NSURLSessionTaskDelegate - 定义了网络请求任务相关的代理方法。
NSURLSessionDownloadDelegate - 用于下载任务相关的代理方法,比如下载进度等等。
NSURLSessionDataDelegate - 用于普通数据任务和上传任务。
我们可以用代理来检测下载进度:
class Downloader:NSObject, NSURLSessionDownloadDelegate {
var session: NSURLSession?
override init() {
super.init()
let imageURL = NSURL(string: "https://httpbin.org/image/png")!
session = NSURLSession(configuration: NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("taask"), delegate: self, delegateQueue: nil)
session?.downloadTaskWithURL(imageURL).resume()
}
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) {
print("下载完成")
}
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
print("正在下载 \(totalBytesWritten)/\(totalBytesExpectedToWrite)")
}
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64) {
print("从 \(fileOffset) 处恢复下载,一共 \(expectedTotalBytes)")
}
}
我们的 Downloader 类实现了 NSURLSessionDownloadDelegate 协议,并实现了这个协议的三个方法,分别用于接收下载完成的通知,下载进度变化的通知,以及下载进度恢复的通知。
注意,Downloader 同时也继承自 NSObject,这个是必须的,否则我们在实现 NSURLSessionDownloadDelegate 协议的方法时会报错。又由于 NSURLSessionDelegate 继承自 NSObjectProtocol,所以我们需要让 Downloader 继承自 NSObject 类,
这个只有在 Swift 中需要显示的继承,在 Objective-C 中则不需要,因为 Objective-C 中的任何类都是继承自 NSObject 的。
后台传输服务
如果是一个BackgroundSession,在Task执行的时候,用户切到后台,Session会和ApplicationDelegate做交互。当程序切到后台后,在BackgroundSession中的Task还会继续下载,这部分文档叙述比较少,现在分三个场景分析下Session和Application的关系:
1、当加入了多个Task,程序没有切换到后台。
这种情况Task会按照NSURLSessionConfiguration的设置正常下载,不会和ApplicationDelegate有交互。
2、当加入了多个Task,程序切到后台,所有Task都完成下载。
在切到后台之后,Session的Delegate不会再收到,Task相关的消息,直到所有Task全都完成后,系统会调用ApplicationDelegate的application:handleEventsForBackgroundURLSession:completionHandler:回调,之后“汇报”下载工作,对于每一个后台下载的Task调用Session的Delegate中的URLSession:downloadTask:didFinishDownloadingToURL:(成功的话)和URLSession:task:didCompleteWithError:(成功或者失败都会调用)。
之后调用Session的Delegate回调URLSessionDidFinishEventsForBackgroundURLSession:。
注意:在ApplicationDelegate被唤醒后,会有个参数ComplietionHandler,这个参数是个Block,这个参数要在后面Session的Delegate中didFinish的时候调用一下,如下:
@implementation APLAppDelegate
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier
completionHandler:(void (^)())completionHandler
{
BLog();
/*
Store the completion handler. The completion handler is invoked by the view controller's checkForAllDownloadsHavingCompleted method (if all the download tasks have been completed).
*/
self.backgroundSessionCompletionHandler = completionHandler;
}
//……
@end
//Session的Delegate
@implementation APLViewController
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
{
APLAppDelegate *appDelegate = (APLAppDelegate *)[[UIApplication sharedApplication] delegate];
if (appDelegate.backgroundSessionCompletionHandler) {
void (^completionHandler)() = appDelegate.backgroundSessionCompletionHandler;
appDelegate.backgroundSessionCompletionHandler = nil;
completionHandler();
}
NSLog(@"All tasks are finished");
}
@end
3、当加入了多个Task,程序切到后台,下载完成了几个Task,然后用户又切换到前台。(程序没有退出)
切到后台之后,Session的Delegate仍然收不到消息。在下载完成几个Task之后再切换到前台,系统会先汇报已经下载完成的Task的情况,然后继续下载没有下载完成的Task,后面的过程同第一种情况。
4、当加入了多个Task,程序切到后台,几个Task已经完成,但还有Task还没有下载完的时候关掉强制退出程序,然后再进入程序的时候。(程序退出了)
最后这个情况比较有意思,由于程序已经退出了,后面没有下完Session就不在了后面的Task肯定是失败了。但是已经下载成功的那些Task,新启动的程序也没有听“汇报”的机会了。经过实验发现,这个时候之前在NSURLSessionConfiguration设置的NSString类型的ID起作用了,当ID相同的时候,一旦生成Session对象并设置Delegate,马上可以收到上一次关闭程序之前没有汇报工作的Task的结束情况(成功或者失败)。但是当ID不相同,这些情况就收不到了,因此为了不让自己的消息被别的应用程序收到,或者收到别的应用程序的消息,起见ID还是和程序的Bundle名称绑定上比较好,至少保证唯一性。
Thanks:
http://blog.csdn.net/jymn_chen/article/details/18937819 NSURLSession学习笔记(一)简介
http://www.cnblogs.com/biosli/p/iOS_Network_URL_Session.html NSURLSession使用说明及后台工作流程分析
https://lvwenhan.com/ios/457.html 自己动手写一个 iOS 网络请求库(四)——快速文件上传
http://www.swiftcafe.io/2015/12/20/nsurlsession/ NSURLSession 网络库 - 原生系统送给我们的礼物
https://realm.io/cn/news/gwendolyn-weston-ios-background-networking/?comefrom=http://blogread.cn/news/ 应用沉睡之时:后台传输服务
https://developer.apple.com/library/mac/documentation/Foundation/Reference/NSURLSession_class/index.html#//apple_ref/occ/cl/NSURLSession NSURLSession
http://www.swiftcafe.io/2015/12/23/nsurlsession-app/ 使用 NSURLSession 开发一个支持后台下载和断点续传的下载工具
相关推荐
NSURLSession的使用 NSURLSession提供了一个可供通过网络下载内容的API,并且具有丰富的代理方法。在iOS中,NSURLSession支持在app未运行或挂起时进行后台下载。此外,NSURLSession原生的支持data、file、ftp、...
在iOS开发中,当我们需要从服务器下载小文件时,NSURLSession提供了一种高效且灵活的解决方案。下面将详细介绍使用NSURLSession进行小文件下载的相关知识点。 ### 1. NSURLSession的基本概念 NSURLSession是由...
下面将详细介绍NSURLSession的使用方法以及相关知识点。 1. **初始化配置** - `NSURLSessionConfiguration`:创建一个会话配置对象,可以设置缓存策略、网络超时时间、Cookie策略等。 - `defaultSession...
本测试主要关注两种常用的网络库:AFNetworking和NSURLSession。两者都是Objective-C编写,且广泛应用于iOS开发中,但各有其特点和优势。下面将详细介绍这两个网络库的使用方法和应用场景。 **AFNetworking** ...
在iOS开发中,`NSURLSession` 是苹果提供的一种用于网络数据传输的高级API,它在iOS 7及以上版本中被引入,取代了之前的`NSURLConnection`。`NSURLSession` 不仅提供了基本的数据请求功能,还支持断点续传、后台下载...
这个压缩包“ios-使用iOS原生NSURLSession简单封装WebService请求.zip”显然包含了一个简单的网络请求封装,利用了苹果的原生网络库NSURLSession。NSURLSession是iOS 7及更高版本中推荐使用的网络编程接口,它提供了...
在iOS开发中,GCD(Grand Central Dispatch)和NSURLSession是两个非常重要的技术,它们在处理多线程和网络请求方面发挥着关键作用。本项目"**GCD+NSURLSession文件下载**"结合了这两个技术,旨在展示如何利用GCD...
在iOS和macOS开发中,Swift语言提供了丰富的API来处理网络任务,其中之一就是NSURLSession,它是一个强大的、高效的网络编程接口。本教程将深入探讨如何利用NSURLSession实现文件的断点续传下载,尤其适用于大文件...
这个"ios-使用NSURLSession进行的下载上传以及断点续传,可多个文件上传.zip"压缩包文件包含了使用NSURLSession实现这些功能的示例代码,名为"WMHSession"。 首先,我们来理解一下NSURLSession的基本概念。...
为了提供高效、稳定且用户友好的下载体验,开发者通常会利用`NSURLSession`框架来实现这一功能。本项目"swift-基于NSURLSession的大文件下载器支持断点下载下载进度等"就是这样一个解决方案,它专门针对大文件下载,...
Swift中的`NSUrlSession`是iOS、macOS等Apple平台进行网络请求的主要API,它提供了高效、灵活且可自定义的网络通信能力。本框架是对`NSUrlSession`的进一步封装,旨在简化网络请求操作,并支持后台下载功能,这对于...
在本教程中,我们将深入探讨如何使用`NSURLSession`来实现文件的下载。 首先,`NSURLSession`是一个面向对象的API,它替代了旧的`NSURLConnection`,提供了多任务支持、更好的性能以及离线缓存等功能。在创建`...
`NSURLSession`是苹果提供的一种强大的网络编程接口,它在iOS 7及更高版本中替代了旧的`NSURLConnection`。本项目“ios-轻量级的基于NSURLSession网络请求工具”提供了一个简单易用的封装,旨在帮助开发者更高效地...
NSURLSession的网络请求类封装CC_HttpTask 可以缓存上一次数据 包含登录后签名 http请求头设置 可二次封装 https://github.com/gwh111/bench_ios github下载地址
在Swift开发中,网络请求是应用与服务器交互的基础,而`NSURLSession`是Apple提供的一个强大的网络编程接口。本文将深入探讨如何对`NSURLSession`进行封装,以实现带有缓存功能的网络请求,包括查看缓存大小和清除...
NSURLSession三种Task的详细Demo。希望对想要学习IOS网络开发的童鞋会有帮助。欢迎关注我的IOS-SDK详解专栏,如果你是个初学者,这里你会找到很多资源。...
基于NSURLSession NSURLProtol的UIWebView离线缓存 主要是使用苹果的黑魔法类:NSURLProtocol来对网络请求进行拦截,拦截后使用自定义的网络去加载数据后进行离线缓存。这样保证在没有网络的情况下,也能保证离线能...
基于NSURLSession NSURLProtol的UIWebView离线缓存 主要是使用苹果的黑魔法类:NSURLProtocol来对网络请求进行拦截,拦截后使用自定义的网络去加载数据后进行离线缓存。这样保证在没有网络的情况下,也能保证离线能...
本教程将深入探讨如何利用`NSURLSession`进行深度封装,实现多任务下载、断点续传、暂停、继续和删除等功能。 首先,我们要理解`NSURLSession`的工作原理。`NSURLSession`是一个基于代理模式的网络请求框架,它可以...