在WWDC 2013中,Apple的团队对NSURLConnection进行了重构,并推出了NSURLSession作为替代。
NSURLSession也是一组相互依赖的类,它的大部分组件和NSURLConnection中的组件相同如NSURLRequest,NSURLCache等。而NSURLSession的不同之处在于,它将NSURLConnection替换为NSURLSession和NSURLSessionConfiguration,以及3个NSURLSessionTask的子类:NSURLSessionDataTask, NSURLSessionUploadTask, 和NSURLSessionDownloadTask。
NSRULSession 网络请求系统包括一个session、一个configuration、一个Task已经Task附带的delegate。一个NSURLSessionConfiguration,总共有三种模式。一个NSURLSessionTask。NSURLSessionTask是抽闲类,对应的代理NSURLSessionTaskDelegate。我们具体使用的时候,会使用他的三种子类,而且每个子类都有对应的delegate。
初始化方法:
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration;
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue;
属性:
delegate: 创建 session 时传入的 delegate,session 对delegate 强引用,只有当 session 执行 invalidate 相关方法后,才会释放引用
delegateQueue: 创建 session 时传入的 delegateQueue,所有的代理方法和 block 回调都会在这个 queue 中执行。
sessionDescription: 可给 session 设置一个描述,用于调试或界面显示。
@property (readonly, retain) NSOperationQueue *delegateQueue;
@property (nullable, readonly, retain) id <NSURLSessionDelegate> delegate;
@property (nullable, copy) NSString *sessionDescription;
创建 task:
可参考NSURLSession
block形式创建并执行block,和delegate一样,Block也有dataTask系列、downloadTask系列、uploadTask系列
获取 session 中的 task:
- (void)getTasksWithCompletionHandler:(void (^)(NSArray<NSURLSessionDataTask *> *dataTasks, NSArray<NSURLSessionUploadTask *> *uploadTasks, NSArray<NSURLSessionDownloadTask *> *downloadTasks))completionHandler;
- (void)getAllTasksWithCompletionHandler:(void (^)(NSArray<__kindof NSURLSessionTask *> *tasks))completionHandler;
设置代理之后的强引用问题
NSURLSession 对象在使用的时候,如果设置了代理,那么 session 会对代理对象保持一个强引用,在合适的时候应该主动进行释放
可以在控制器调用 viewDidDisappear 方法的时候来进行处理,可以通过调用 invalidateAndCancel 方法或者是 finishTasksAndInvalidate 方法来释放对代理对象的强引用.
invalidateAndCancel 方法直接取消请求然后释放代理对象,
finishTasksAndInvalidate 方法等请求完成之后释放代理对象
- (void)finishTasksAndInvalidate;
- (void)invalidateAndCancel;
一、NSURLSessionConfiguration类
里面所有属性的设置都是对当前NSURLSession的整体设置。NSURLSessionConfiguration会话配置
默认会话模式(default):工作模式类似于原来的NSURLConnection,使用的是基于磁盘缓存的持久化策略,使用用户keychain中保存的证书进行认证授权。
瞬时会话模式(ephemeral):该模式不使用磁盘保存任何数据。所有和会话相关的caches,证书,cookies等都被保存在RAM中,因此当程序使会话无效,这些缓存的数据就会被自动清空。
后台会话模式(background):该模式在后台完成上传和下载,在创建Configuration对象的时候需要提供一个NSString类型的ID用于标识完成工作的后台会话。
+ (NSURLSessionConfiguration *)defaultSessionConfiguration;
+ (NSURLSessionConfiguration *)ephemeralSessionConfiguration;
+ (NSURLSessionConfiguration *)backgroundSessionConfiguration:(NSString *)identifier;
//方法中的identifier参数指定了会话的ID,用于标记后台的session。
timeoutIntervalForRequest: 指定了请求以及该资源的超时时间间隔, 当新数据到达时,与该值相关联的计时器将被重置。默认60s
timeoutIntervalForResource: 这应该只用于后台传输,默认7天
@property NSTimeInterval timeoutIntervalForRequest;
@property NSTimeInterval timeoutIntervalForResource;
networkServiceType对标准的网络流量,网络电话,语音,视频,以及由一个后台进程使用的流量进行了区分。设置后便于系统对网络请求的区分,系统能根据提供的信息来优化网络处理,从而优化电池寿命,网络性能等等
@property NSURLRequestNetworkServiceType networkServiceType;
allowsCellularAccess: 属性指定是否允许使用蜂窝连接;
discretionary: 属性为YES时表示当程序在background运作时由系统自己选择最佳的网络连接配置,该属性可以节省通过蜂窝连接的带宽。在使用后台传输数据的时候,建议使用discretionary属性,而不是allowsCellularAccess属性,因为它会把WiFi和电源可用性考虑在内。
@property BOOL allowsCellularAccess;
@property (getter=isDiscretionary) BOOL discretionary NS_AVAILABLE(NA, 7_0);
此属性根据此配置确定会话中的任务对每个主机的最大并发连接数。MacOS中的默认值为6,iOS中为4.如果有多个会话,会超过这个限制
@property NSInteger HTTPMaximumConnectionsPerHost;
HTTPShouldUsePipelining表示receiver(理解为iOS客户端)的下一个信息是否必须等到上一个请求回复才能发送。
如果为YES表示可以,NO表示必须等receiver收到先前的回复才能发送下个信息。默认为NO
@property BOOL HTTPShouldUsePipelining;
Cookies是一种能够让网站服务器把少量数据储存到客户端的硬盘或内存,或是从客户端的硬盘读取数据的一种技术。Cookies是当你浏览某网站时,由Web服务器置于你硬盘上的一个非常小的文本文件,它可以记录你的用户ID、密码、浏览过的网页、停留的时间等信息。当你再次来到该网站时,网站通过读取Cookies,得知你的相关信息,就可以做出相应的动作,如在页面显示欢迎你的标语,或者让你不用输入ID、密码就直接登录等等。默认为YES
@property BOOL HTTPShouldSetCookies;
//Cookie数据的接收协议(接收所有,不接收,默认只接受主文档)
@property NSHTTPCookieAcceptPolicy HTTPCookieAcceptPolicy;
//Cookie 处理类 [详解](http://www.jb51.net/article/88173.htm)
@property (nullable, retain) NSHTTPCookieStorage *HTTPCookieStorage;
是会话使用的证书存储。默认情况下,NSURLCredentialStorage 的+ sharedCredentialStorage 会被使用使用
@property (nullable, retain) NSURLCredentialStorage *URLCredentialStorage;
@property (nullable, retain) NSURLCache *URLCache;
指定了一组默认的可以设置出站请求的数据头
@property (nullable, copy) NSDictionary *HTTPAdditionalHeaders;
NSHTTPCookieStorage
NSURLRequest都会帮你主动记录下来你访问的站点设置的 cookie,而且很负责任的,当你下次再访问这个站点时,NSURLRequest会拿着上次保存下来了的cookie继续去请求。
NSHttpCookiesStorage是一个单例,管理所有的Cookie,每个Cookie都是一个NSHTTPCookie的实例,所有应用的cookies都被保存在这个NSHTTPCookieStorage的单例中,并且跨进程同步。 但为了安全,每个应用都有自己的沙盒,A应用的cookie是不能被B应用访问的。
查看cookie
NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (NSHTTPCookie *cookie in [cookieJar cookies]) {
NSLog(@"%@", cookie);
}
清空cookie
NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray *_tmpArray = [NSArray arrayWithArray:[cookieJar cookies]];
for (id obj in _tmpArray) {
[cookieJar deleteCookie:obj];
}
指定cookie
NSMutableDictionary *cookieProperties = [NSMutableDictionary dictionary];
[cookieProperties setObject:@"username" forKey:NSHTTPCookieName];
[cookieProperties setObject:@"rainbird" forKey:NSHTTPCookieValue];
[cookieProperties setObject:@"cnrainbird.com" forKey:NSHTTPCookieDomain];
[cookieProperties setObject:@"cnrainbird.com" forKey:NSHTTPCookieOriginURL];
[cookieProperties setObject:@"/" forKey:NSHTTPCookiePath];
[cookieProperties setObject:@"0" forKey:NSHTTPCookieVersion];
NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieProperties];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
NSURLCache
在应用程序的开发中,为了减小对网络的依赖,提高程序性能,常常会对一些非实时性的数据进行缓存处理,NSURLCache类用于管理NSURLRequest请求缓存。
缓存的实现说明:由于GET请求一般用来查询数据,POST请求一般是发大量数据给服务器处理(变动性比较大),因此一般只对GET请求进行缓存,而不对POST请求进行缓存。
SURLCache的常见用法:
获得全局缓存对象(没必要手动创建)
NSURLCache *cache = [NSURLCache sharedURLCache];
设置内存缓存的最大容量(字节为单位,默认为512KB)
设置硬盘缓存的最大容量 (字节为单位,默认为10M)
@property NSUInteger memoryCapacity;
@property NSUInteger diskCapacity;
@property (readonly) NSUInteger currentMemoryUsage;
取得某个请求的缓存,存储缓存
- (nullable NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request;
- (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse forRequest:(NSURLRequest *)request;
清除缓存
- (void)removeCachedResponseForRequest:(NSURLRequest *)request;
- (void)removeAllCachedResponses;
- (void)removeCachedResponsesSinceDate:(NSDate *)date NS_AVAILABLE(10_10, 8_0);
二、NSURLSessionTask类
可以参考这篇文章AFNetWorking源码之NSURLSession系列概述
从上面我们发现Task和delegate有一套对应的继承关系:
从继承关系上,我们就可以理解在初始化的时候,只通过设置NSURLSession对象的delegate就可以了。因为根据不同的task,其实就是设置了不同的delegate。这个设计避免了多次设置delegate的情况,同时也根据不同的task实现不同的delegate方法。
NSURLSessionTask的属性和方法
@property (readonly) NSUInteger taskIdentifier;
@property (nullable, readonly, copy) NSURLRequest *originalRequest;
@property (nullable, readonly, copy) NSURLRequest *currentRequest;
@property (nullable, readonly, copy) NSURLResponse *response;
//task优先级
@property float priority
//当前接收量
@property (readonly) int64_t countOfBytesReceived;
//当前发送量
@property (readonly) int64_t countOfBytesSent;
//发送数据总数
@property (readonly) int64_t countOfBytesExpectedToSend;
//接收数据总数,来源于响应头Content-Length字段
@property (readonly) int64_t countOfBytesExpectedToReceive;
//cancel方法可以取消当前的任务,你也可以向处于suspend状态的任务发送cancel消息,任务如果被取消便不能再恢复到之前的状态.
- (void)cancel;
//suspend可以让当前的任务暂停
- (void)suspend;
//resume方法不仅可以启动任务,还可以唤醒suspend状态的任务
- (void)resume;
1、代理说明
NSURLSessionDelegate
当一个session遇到系统错误或者未检测到的错误的时候,就会调用这个方法。
- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error
当请求需要认证、或者https证书认证的时候,我们就需要在这个方法里面处理。
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler
如果应用进入后台、这个方法会被调用。我们在这里可以对session发起的请求做各种操作比如请求完成的回调等。
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
NSURLSessionTaskDelegate
当请求重定向的时候调用这个方法。我们必须设置一个新的NSURLRequest
对象传入completionHandler来重定向新的请求,但是当session
是background模式的时候,这个方法不会被调用。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
newRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler{
}
当请求需要认证的时候调用这个方法。如果没有实现这个代理,那么请求认证这个过程不会被调用。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler{
}
如果请求需要一个新的请求体时,这个方法就会被调用。比如认证失败的时候,我们可以通过这个机会从新认证。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
needNewBodyStream:(void (^)(NSInputStream * _Nullable bodyStream))completionHandler
当我们上传数据的时候,我们可以通过这个代理方法获取上传进度。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didSendBodyData:(int64_t)bytesSent
totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
当task的统计信息收集好了以后,调用这个方法。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics
当一个task出错的时候,会调用这个方法。如果error是nil,也会调用这个方法,表示task完成。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didCompleteWithError:(nullable NSError *)error{
NSLog(@"数据返回以后,不管有错没错都回调用,如果没错,error及时nil");
}
NSURLSessionDataDelegate
当一个task接收到返回信息。当所有信息都接收完毕以后,completionHandler会被调用。我们可以在这里取消一个网络请求或者把一个datatask转换为downloadtask。如果没有实现这个代理方法,我们也可以通过task的response属性获取到对应的数据。background模式的uploadtask不会调用这个方法。
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
当一个datatask转换为一个downloadtask以后会调用。
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask{
// 允许处理服务器的响应,才会继续接收服务器返回的数据
completionHandler(NSURLSessionResponseAllow);
}
当data可以使用的时候,调用这个方法。我们可以在这里获取data。
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data
允许我们在这里调用completionHandler缓存data,或者传入nil来禁止缓存
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
willCacheResponse:(NSCachedURLResponse *)proposedResponse
completionHandler:(void (^)(NSCachedURLResponse * _Nullable cachedResponse))completionHandler{
}
NSURLSessionDownloadDelegate
当一个下载task任务完成以后,这个方法会被调用。我们可以在这里移动或者复制download的数据
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
获取下载进度
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
断点下载。如果下载出错,NSURLSessionDownloadTaskResumeData里面包含重新开始下载的数据。
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes
2、NSURLSession子类
NSURLSessionDataTask
GET请求:
// 快捷方式获得session对象
NSURLSession *session = [NSURLSession sharedSession];
NSURL *url = [NSURL URLWithString:@"http://www.daka.com/login?username=daka&pwd=123"];
// 通过URL初始化task,在block内部可以直接对返回的数据进行处理
NSURLSessionTask *task = [session dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError error) {
NSLog(@"%@", [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]);
}];
// 启动任务
[task resume]
POST请求:
NSURL *url = [NSURL URLWithString:@"http://www.daka.com/login"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
request.HTTPBody = [@"username=daka&pwd=123" dataUsingEncoding:NSUTF8StringEncoding];
NSURLSession *session = [NSURLSession sharedSession];
// 由于要先对request先行处理,我们通过request初始化task
NSURLSessionTask *task = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSLog(@"%@", [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]); }];
[task resume];
NSURLSessionDataDelegate代理方法:
// 使用代理方法需要设置代理,但是session的delegate属性是只读的,要想设置代理只能通过这种方式创建session
//delegateQueue参数表示协议方法将会在哪个队列(NSOperationQueue)里面执行.
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
delegate:self
delegateQueue:[[NSOperationQueue alloc] init]];
// 创建任务(因为要使用代理方法,就不需要block方式的初始化了)
NSURLSessionDataTask *task = [session dataTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.daka.com/login?userName=daka&pwd=123"]]];
// 启动任务
[task resume];
//对应的代理方法如下:
// 1.接收到服务器的响应
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
// 允许处理服务器的响应,才会继续接收服务器返回的数据
completionHandler(NSURLSessionResponseAllow);
}
// 2.接收到服务器的数据(可能调用多次)
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
// 处理每次接收的数据
}
// 3.请求成功或者失败(如果失败,error有值)
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
// 请求完成,成功或者失败的处理
}
NSURLSessionDownloadTask
普通下载:
NSURLSessionDownloadTask同样提供了通过NSURL和NSURLRequest两种方式来初始化并通过block进行回调的方法.下面以NSURL初始化:
NSURLSession *session = [NSURLSession sharedSession];
NSURL *url = [NSURL URLWithString:@"http://www.daka.com/resources/image/icon.png"] ;
NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
// location是沙盒中tmp文件夹下的一个临时url,文件下载后会存到这个位置,由于tmp中的文件随时可能被删除,所以我们需要自己需要把下载的文件挪到需要的地方
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];
// 剪切文件
[[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:path] error:nil];
}];
// 启动任务
[task resume];
downloadTask也提供了配套的代理方法:
// NSURLSessionConfiguration 方式创建 NSURLSession ,调用代理方法
NSURLSessionConfiguration *defaultConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
self.currentSession = [NSURLSession sessionWithConfiguration:defaultConfig delegate:self delegateQueue:nil];
self.currentSession.sessionDescription = kCurrentSession;
[self.cancellableTask resume];
// 每次写入调用(会调用多次) 实现下载进度的显示
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
// 可在这里通过已写入的长度和总长度算出下载进度
CGFloat progress = 1.0 * totalBytesWritten / totalBytesExpectedToWrite; NSLog(@"%f",progress);
}
// 下载完成调用
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location {
// location还是一个临时路径,需要自己挪到需要的路径(caches下面)
NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
[[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:filePath] error:nil];
}
// 任务完成调用
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
}
断点下载:
NSURLSession的这种断点下载只支持应用内断点,如果程序在下载过程中途关闭,则不能恢复下载.
// 使用这种方式取消下载可以得到将来用来恢复的数据,保存起来
[self.task cancelByProducingResumeData:^(NSData *resumeData) {
self.resumeData = resumeData;
}];
// 由于下载失败导致的下载中断会进入此协议方法,也可以得到用来恢复的数据
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
// 保存恢复数据
self.resumeData = error.userInfo[NSURLSessionDownloadTaskResumeData];
}
// 恢复下载时接过保存的恢复数据
self.task = [self.session downloadTaskWithResumeData:self.resumeData];
// 启动任务
[self.task resume];
/* 另外在恢复下载时,NSURLSessionDownloadDelegate中的以下方法将被调用,从fileOffset位移处恢复下载任务 */
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes {
NSLog(@"NSURLSessionDownloadDelegate: Resume download at %lld", fileOffset);
}
后台下载:
首先创建一个后台session单例,这里的Session配置使用后台配置模式,使用backgroundSessinConfiguration:方法配置时应该通过后面的参数为该后台进程指定一个标识符,在有多个后台下载任务时这个标识符就起作用了。
/* 1、创建一个后台session单例 */
- (NSURLSession *)backgroundSession {
static NSURLSession *backgroundSess = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSURLSessionConfiguration *config = [NSURLSessionConfiguration backgroundSessionConfiguration:kBackgroundSessionID];
backgroundSess = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
backgroundSess.sessionDescription = kBackgroundSession;
});
return backgroundSess;
}
/* 2、在创建后台下载任务时,应该使用后台session创建,然后resume。*/
- (IBAction)backgroundDownload:(id)sender {
NSString *imageURLStr = @"http://farm3.staticflickr.com/2831/9823890176_82b4165653_b_d.jpg";
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:imageURLStr]];
self.backgroundTask = [self.backgroundSession downloadTaskWithRequest:request];
[self setDownloadButtonsWithEnabled:NO];
self.downloadedImageView.image = nil;
[self.backgroundTask resume];
}
/*3 在程序进入后台后,如果下载任务完成,程序委托中的对应方法将被回调:*/
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {
NSLog(@"Application Delegate: Background download task finished");
// 设置回调的完成代码块
self.backgroundURLSessionCompletionHandler = completionHandler;
}
/*4、然后调用NSURLSessionDownloadDelegate中的方法:(该方法只有下载成功才被调用)*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL*)location{
else if (session == self.backgroundSession) {
self.backgroundTask = nil;
AppDelegate *appDelegate = [AppDelegate sharedDelegate];
if (appDelegate.backgroundURLSessionCompletionHandler) {
// 执行回调代码块
void (^handler)() = appDelegate.backgroundURLSessionCompletionHandler;
appDelegate.backgroundURLSessionCompletionHandler = nil;
handler();
}
}
/*5、 完成下载任务,无论下载成功还是失败都调用该方法 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
NSLog(@"NSURLSessionDownloadDelegate: Complete task");
dispatch_async(dispatch_get_main_queue(), ^{
[self setDownloadButtonsWithEnabled:YES];
});
if (error) {
NSLog(@"下载失败:%@", error);
[self setDownloadProgress:0.0];
self.downloadedImageView.image = nil;
}
}
NSURLSessionUploadTask
在NSURLSession中,文件上传方式主要有以下两种:
NSURLSessionUploadTask *task =
[[NSURLSession sharedSession] uploadTaskWithRequest:request
fromFile:fileName
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
}];
//我们会使用POST方式进行文件上传,所以较多使用第二种方式
[self.session uploadTaskWithRequest:request
fromData:body
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(@"-------%@", [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]);
}];
三、NSURLRequest
初始化方法:
//通过这种方式创建的请求对象 默认使用NSURLRequestUseProtocolCachePolicy缓存逻辑 默认请求超时时限为60s
+ (instancetype)requestWithURL:(NSURL *)URL;
+ (instancetype)requestWithURL:(NSURL *)URL cachePolicy:(NSURLRequestCachePolicy)cachePolicy timeoutInterval:(NSTimeInterval)timeoutInterval;
//init方法进行对象的创建 默认使用NSURLRequestUseProtocolCachePolicy缓存逻辑 默认请求超时时限为60s
- (instancetype)initWithURL:(NSURL *)URL;
- (instancetype)initWithURL:(NSURL *)URL cachePolicy:(NSURLRequestCachePolicy)cachePolicy timeoutInterval:(NSTimeInterval)timeoutInterval NS_DESIGNATED_INITIALIZER;
常用属性:
只读属性 获取请求的超时时限
@property (readonly) NSTimeInterval timeoutInterval;
主文档地址 这个地址用来存放缓存
@property (nullable, readonly, copy) NSURL *mainDocumentURL;
获取网络请求的服务类型
获取是否允许使用服务商蜂窝网络
@property (readonly) NSURLRequestNetworkServiceType networkServiceType
@property (readonly) BOOL allowsCellularAccess
@property (nullable, readonly, copy) NSDictionary<NSString *, NSString *> *allHTTPHeaderFields;
- (nullable NSString *)valueForHTTPHeaderField:(NSString *)field;
NSMutableURLRequest
继承于NSURLRequest
常用属性:
//设置请求的URL
@property (nullable, copy) NSURL *URL;
//设置请求的缓存策略
@property NSURLRequestCachePolicy cachePolicy;
//设置超时时间
@property NSTimeInterval timeoutInterval;
//设置缓存目录
@property (nullable, copy) NSURL *mainDocumentURL;
//设置网络服务类型
@property NSURLRequestNetworkServiceType networkServiceType NS_AVAILABLE(10_7, 4_0);
//设置是否允许使用服务商蜂窝网
@property BOOL allowsCellularAccess NS_AVAILABLE(10_8, 6_0);
以下属性的设置必须使用NSMutableURLRequest类,HTTP/HTTPS协议相关请求的属性设置,如果是NSURLRequest,则只可以读,不可以修改。
//设置HPPT请求方式 默认为“GET”
@property (copy) NSString *HTTPMethod;
//通过字典设置HTTP请求头的键值数据
@property (nullable, copy) NSDictionary<NSString *, NSString *> *allHTTPHeaderFields;
//设置http请求头中的字段值
- (void)setValue:(nullable NSString *)value forHTTPHeaderField:(NSString *)field;
//向http请求头中添加一个字段
- (void)addValue:(NSString *)value forHTTPHeaderField:(NSString *)field;
//设置http请求体 用于POST请求
@property (nullable, copy) NSData *HTTPBody;
//设置http请求体的输入流
@property (nullable, retain) NSInputStream *HTTPBodyStream;
//设置发送请求时是否发送cookie数据
@property BOOL HTTPShouldHandleCookies;
//管道线技术,设置请求时是否按顺序收发 默认禁用 在某些服务器中设为YES可以提高网络性能
@property BOOL HTTPShouldUsePipelining;
四、NSURLResponse
初始化方法不经常用到,略。
常用的属性:
//服务的URL地址
@property (nullable, readonly, copy) NSURL *URL;
//返回的数据信息(纯文本,视频,语音,超文本等)
@property (nullable, readonly, copy) NSString *MIMEType;
//将要返回的数据的大小
@property (readonly) long long expectedContentLength;
//编码的名称
@property (nullable, readonly, copy) NSString *textEncodingName;
//获取服务器的文件的名称
@property (nullable, readonly, copy) NSString *suggestedFilename;
NSHTTPURLResponse
继承于NSURLResponse
SInteger statusCode:返回的状态码,成功,失败,无效请求等,(200,404,400等)
NSDictionary* allHeaderFields:返回数据的头部信息,key-value格式
@property (readonly) NSInteger statusCode;
@property (readonly, copy) NSDictionary *allHeaderFields;