浅析NSURLConnection和NSURLSession

1,372 阅读15分钟

概述

NSURLConnection和NSURLSession是iOS开发中的两大网络请求API,NSURLConnection是2003年伴随着Safari一起发行的网络开发API,距今已经有十一年。当然,在这十一年间它表现的相当优秀,有大量的应用基础,但是这些年伴随着iPhone、iPad的发展,对于NSURLConnection设计理念也提出了新的挑战。在2013年WWDC上苹果揭开了NSURLSession的面纱,将它作为NSURLConnection的继任者。相比较NSURLConnection,NSURLSession提供了配置会话缓存、协议、cookie和证书能力,这使得网络架构和应用程序可以独立工作、互不干扰。另外,NSURLSession另一个重要的部分是会话任务,它负责加载数据,在客户端和服务器端进行文件的上传下载。

NSURLConnection

注意:此 API 已经被apple标记过时,请改用 URLSession。

NSURLConnection 对象允许您通过提供 URL 请求对象来加载 URL 的内容。 NSURLConnection 的接口是简朴的,仅提供用于启动和取消URL异步加载请求的的api。 URL请求对象本身包含大部分请求配置。

尽管NSURLConnection的实例通常称为“连接”,但这些对象与底层网络连接之间并没有 1:1 的相关性。

NSURLConnection 类提供了方便的类方法来使用block块异步和同步加载 URL 请求。

为了更好地控制,您可以使用符合 NSURLConnectionDelegate 和 NSURLConnectionDataDelegate 协议的委托对象创建 URL 连接对象。当 URL 请求异步加载时,连接调用该委托上的方法为您提供进度和状态。连接还调用委托方法,让您覆盖连接的默认行为(例如,指定应如何处理特定重定向)。在启动异步加载操作的线程上调用这些委托方法。

注意:在请求期间,连接保持对其委托的强引用。当连接完成加载、失败或被取消时,它会释放该强引用。

  • NSURLConnection 协议 NSURLConnection 类与三个正式协议协同工作:NSURLConnectionDelegate、NSURLConnectionDataDelegate 和 NSURLConnectionDownloadDelegate。要使用这些协议,您需要编写一个符合它们的类并实现任何适当的方法,然后在创建连接对象时提供该类的一个实例作为委托。

NSURLConnectionDelegate 协议主要用于凭证处理,但也处理连接完成。因为它在数据传输期间处理连接失败,所以所有连接委托通常都必须实现此协议。

NSURLConnectionDataDelegate 协议,该协议提供了 NSURLConnection 类调用的方法,其中包含上传期间的进度信息、下载期间的响应数据片段,以及如果服务器的响应需要第二次连接尝试,则提供新的上传主体流——例如,如果 NSURLConnection 必须使用不同的凭据重试请求。

NSURLConnectionDownloadDelegate 协议。此协议支持继续中断文件下载并在下载完成时接收通知。该协议仅用于使用 Newsstand Kit 的 download(with:) 方法创建的 NSURLConnection 对象。

NSURLConnection的使用

  • 1,同步请求:
-(void)sendSynchronousRequest{
    //1、创建一个URL
    //协议头+主机地址+接口名称+?+参数1&参数2&参数3
    //这里的话是我自己使用.Net开发的一个本地后台接口 http://192.168.1.0:8080/login?username=LitterL&pwd=123
    NSURL *url = [NSURL URLWithString:@"http://192.168.1.0:8080/login?username=LitterL&pwd=123"];

    //2、创建请求(Request)对象(默认为GET请求);
    NSURLRequest *requst = [[NSURLRequest alloc]initWithURL:url];

    //3、发送请求
    /*
     第一个参数:请求对象
     第二个参数:响应头
     第三个参数:错误信息
     返回值:NSData类型,响应体信息
     */
    NSError *error = nil;
    NSURLResponse *response = nil;
    //发送同步请求(sendSynchronousRequest)
    NSData *data = [NSURLConnection sendSynchronousRequest:requst returningResponse:&response error:&error];
    //如果没有错误就执行
    if (!error) {
        //打印的服务端返回的信息以及错误信息
        NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
        NSLog(@"%@",error);
    }
}
  • 2,异步请求:
-(void)sendAsynchronousRequest{
    //1、创建一个URL
    NSURL *url = [NSURL URLWithString:@"http://192.168.1.0:8080/login"];

    //2、创建请求(Request)对象 这里使用的是它的子类NSMutableURLRequest,因为子类才具有设置方法和设置请求体的属性
    NSMutableURLRequest *requst = [[NSMutableURLRequest alloc]initWithURL:url];
    //2.1、设置请求方法
    requst.HTTPMethod = @"POST";
    //2.2、设置请求体,因为传入的为Data数据所有这里需要转换
    requst.HTTPBody = [@"username=LitterL&pwd=123" dataUsingEncoding:NSUTF8StringEncoding];
    //2.3、设置请求超时时间,如果超过这个时间,请求为失败
    requst.timeoutInterval = 10;

    //3、发送请求

    /*
     第一个参数:请求对象
     第二个参数:队列
     第三个参数:Block回调函数
        response:响应头
        data:响应体信息
        connectionError:错误信息
     */

    //发送异步请求(sendAsynchronousRequest)
    [NSURLConnection sendAsynchronousRequest:requst queue:[[NSOperationQueue alloc]init] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
        NSLog(@"----%@",[NSThread currentThread]);

        //解析数据
        NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
    }];
}
  • 3,委托代理:

//调用的方法
-(void)sendRequestWithDelegate{
   //1.确定请求路径
   NSURL *url = [NSURL URLWithString:@"http://192.168.1.0:8080/login?username=LitterL&pwd=123"];
   //2.创建请求对象
   NSURLRequest *request = [NSURLRequest requestWithURL:url];

   //3、代理请求
   /*
    第一个参数:请求对象
    第二个参数:谁成为代理
    第三个参数:startImmediately :是否立即开始发送网络请求
    */
   NSURLConnection *connect = [[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:NO];
   //[connect cancel]; 取消
   [connect start];
}


//2、实现代理中的四个方法
//1.当接受到服务器响应的时候会调用:response(响应头)
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
   NSLog(@"接受到相应");
}

//2.当接受到服务器返回数据的时候调用(会调用多次)
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
   //
   NSLog(@"接受到数据");
   //拼接数据
   [self.fileData appendData:data];
}

//3.当请求失败的时候调用
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
   NSLog(@"请求失败");
}

//4.当请求结束(成功|失败)的时候调用
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
   NSLog(@"请求结束");

   //解析数据
   NSLog(@"%@",[[NSString alloc]initWithData:self.fileData encoding:NSUTF8StringEncoding]);
}

NSURLSession

NSURLConnection完成的三个主要任务:获取数据(通常是JSON、XML等)、文件上传、文件下载。其实在NSURLSession时代,他们分别由三个任务来完成:NSURLSessionData、NSURLSessionUploadTask、NSURLSessionDownloadTask,这三个类都是NSURLSessionTask这个抽象类的子类,相比直接使用NSURLConnection,NSURLSessionTask支持任务的暂停、取消和恢复,并且默认任务运行在其他非主线程中,具体关系图如下:

image.png

数据请求

前面通过请求一个微博数据进行数据请求演示,现在通过NSURLSessionDataTask实现这个功能,其实现流程与使用NSURLConnection的静态方法类似,下面是主要代码:

-(void)loadJsonData{
    //1.创建url
    NSString *urlStr=[NSString stringWithFormat:@"http://192.168.1.208/ViewStatus.aspx?userName=%@&password=%@",@"KenshinCui",@"123"];
    urlStr =[urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url=[NSURL URLWithString:urlStr];
    //2.创建请求
    NSURLRequest *request=[NSURLRequest requestWithURL:url];
    
    //3.创建会话(这里使用了一个全局会话)并且启动任务
    NSURLSession *session=[NSURLSession sharedSession];
    //从会话创建任务
    NSURLSessionDataTask *dataTask=[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (!error) {
            NSString *dataStr=[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"%@",dataStr);
        }else{
            NSLog(@"error is :%@",error.localizedDescription);
        }
    }];
    
    [dataTask resume];//恢复线程,启动任务
}

文件上传

下面看一下如何使用NSURLSessionUploadTask实现文件上传,这里贴出主要的几个方法:

#pragma mark 取得mime types
-(NSString *)getMIMETypes:(NSString *)fileName{
    return @"image/jpg";
}
#pragma mark 取得数据体
-(NSData *)getHttpBody:(NSString *)fileName{
    NSString *boundary=@"KenshinCui";
    NSMutableData *dataM=[NSMutableData data];
    NSString *strTop=[NSString stringWithFormat:@"--%@\nContent-Disposition: form-data; name=\"file1\"; filename=\"%@\"\nContent-Type: %@\n\n",boundary,fileName,[self getMIMETypes:fileName]];
    NSString *strBottom=[NSString stringWithFormat:@"\n--%@--",boundary];
    NSString *filePath=[[NSBundle mainBundle] pathForResource:fileName ofType:nil];
    NSData *fileData=[NSData dataWithContentsOfFile:filePath];
    [dataM appendData:[strTop dataUsingEncoding:NSUTF8StringEncoding]];
    [dataM appendData:fileData];
    [dataM appendData:[strBottom dataUsingEncoding:NSUTF8StringEncoding]];
    return dataM;
}
#pragma mark 上传文件
-(void)uploadFile{
    NSString *fileName=@"pic.jpg";
    //1.创建url
    NSString *urlStr=@"http://192.168.1.208/FileUpload.aspx";
    urlStr =[urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url=[NSURL URLWithString:urlStr];
    //2.创建请求
    NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:url];
    request.HTTPMethod=@"POST";
    
    //3.构建数据
    NSString *path=[[NSBundle mainBundle] pathForResource:fileName ofType:nil];
    NSData *data=[self getHttpBody:fileName];
    request.HTTPBody=data;
    
    [request setValue:[NSString stringWithFormat:@"%lu",(unsigned long)data.length] forHTTPHeaderField:@"Content-Length"];
    [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",@"KenshinCui"] forHTTPHeaderField:@"Content-Type"];
    
    

    //4.创建会话
    NSURLSession *session=[NSURLSession sharedSession];
    NSURLSessionUploadTask *uploadTask=[session uploadTaskWithRequest:request fromData:data completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (!error) {
            NSString *dataStr=[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"%@",dataStr);
        }else{
            NSLog(@"error is :%@",error.localizedDescription);
        }
    }];
    
    [uploadTask resume];
}

文件下载

使用NSURLSessionDownloadTask下载文件的过程与前面差不多,需要注意的是文件下载文件之后会自动保存到一个临时目录,需要开发人员自己将此文件重新放到其他指定的目录中。

-(void)downloadFile{
    //1.创建url
    NSString *fileName=@"1.jpg";
    NSString *urlStr=[NSString stringWithFormat: @"http://192.168.1.208/FileDownload.aspx?file=%@",fileName];
    urlStr =[urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url=[NSURL URLWithString:urlStr];
    //2.创建请求
    NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:url];
    
    //3.创建会话(这里使用了一个全局会话)并且启动任务
    NSURLSession *session=[NSURLSession sharedSession];
    
    NSURLSessionDownloadTask *downloadTask=[session downloadTaskWithRequest:request completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
        if (!error) {
            //注意location是下载后的临时保存路径,需要将它移动到需要保存的位置
            
            NSError *saveError;
            NSString *cachePath=[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
            NSString *savePath=[cachePath stringByAppendingPathComponent:fileName];
            NSLog(@"%@",savePath);
            NSURL *saveUrl=[NSURL fileURLWithPath:savePath];
            [[NSFileManager defaultManager] copyItemAtURL:location toURL:saveUrl error:&saveError];
            if (!saveError) {
                NSLog(@"save sucess.");
            }else{
                NSLog(@"error is :%@",saveError.localizedDescription);
            }
            
        }else{
            NSLog(@"error is :%@",error.localizedDescription);
        }
    }];
    
    [downloadTask resume];
}

会话

NSURLConnection通过全局状态来管理cookies、认证信息等公共资源,这样如果遇到两个连接需要使用不同的资源配置情况时就无法解决了,但是这个问题在NSURLSession中得到了解决。NSURLSession同时对应着多个连接,会话通过工厂方法来创建,同一个会话中使用相同的状态信息。NSURLSession支持进程三种会话:

  1. defaultSessionConfiguration:进程内会话(默认会话),用硬盘来缓存数据。
  2. ephemeralSessionConfiguration:临时的进程内会话(内存),不会将cookie、缓存储存到本地,只会放到内存中,当应用程序退出后数据也会消失。
  3. backgroundSessionConfiguration:后台会话,相比默认会话,该会话会在后台开启一个线程进行网络数据处理。
#pragma mark 文件下载
-(void)downloadFile{
    //1.创建url
    NSString *fileName=_textField.text;
    NSString *urlStr=[NSString stringWithFormat: @"http://192.168.1.208/FileDownload.aspx?file=%@",fileName];
    urlStr =[urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url=[NSURL URLWithString:urlStr];
    //2.创建请求
    NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:url];
    
    //3.创建会话
    //默认会话
    NSURLSessionConfiguration *sessionConfig=[NSURLSessionConfiguration defaultSessionConfiguration];
    sessionConfig.timeoutIntervalForRequest=5.0f;//请求超时时间
    sessionConfig.allowsCellularAccess=true;//是否允许蜂窝网络下载(2G/3G/4G)
    //创建会话
    NSURLSession *session=[NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil];//指定配置和代理
    _downloadTask=[session downloadTaskWithRequest:request];

    [_downloadTask resume];
}
#pragma mark 取消下载
-(void)cancelDownload{
    [_downloadTask cancel];
    
}
#pragma mark 挂起下载
-(void)suspendDownload{
    [_downloadTask suspend];
}
#pragma mark 恢复下载下载
-(void)resumeDownload{
    [_downloadTask resume];
}

#pragma mark - 下载任务代理
#pragma mark 下载中(会多次调用,可以记录下载进度)
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
    [self setUIStatus:totalBytesWritten expectedToWrite:totalBytesExpectedToWrite];
}

#pragma mark 下载完成
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
    NSError *error;
    NSString *cachePath=[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    NSString *savePath=[cachePath stringByAppendingPathComponent:_textField.text];
    NSLog(@"%@",savePath);
    NSURL *saveUrl=[NSURL fileURLWithPath:savePath];
    [[NSFileManager defaultManager] copyItemAtURL:location toURL:saveUrl error:&error];
    if (error) {
        NSLog(@"Error is:%@",error.localizedDescription);
    }
}

#pragma mark 任务完成,不管是否下载成功
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
    [self setUIStatus:0 expectedToWrite:0];
    if (error) {
        NSLog(@"Error is:%@",error.localizedDescription);
    }
}

后台任务

NSURLSession支持程序的后台下载和上传,苹果官方将其称为进程之外的上传和下载,这些任务都是交给后台守护线程完成的,而非应用程序本身。即使文件在下载和上传过程中崩溃了也可以继续运行(注意如果用户强制退关闭应用程序,NSURLSession会断开连接)。下面看一下如何在后台进行文件下载,这在实际开发中往往很有效,例如在手机上缓存一个视频在没有网络的时候观看(为了简化程序这里不再演示任务的取消、挂起等操作)。下面对前面的程序稍作调整使程序能在后台完成下载操作:


#pragma mark 取得一个后台会话(保证一个后台会话,这通常很有必要)
-(NSURLSession *)backgroundSession{
    static NSURLSession *session;
    static dispatch_once_t token;
    dispatch_once(&token, ^{
        NSURLSessionConfiguration *sessionConfig=[NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"com.cmjstudio.URLSession"];
        sessionConfig.timeoutIntervalForRequest=5.0f;//请求超时时间
        sessionConfig.discretionary=YES;//系统自动选择最佳网络下载
        sessionConfig.HTTPMaximumConnectionsPerHost=5;//限制每次最多一个连接
        //创建会话
        session=[NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil];//指定配置和代理
    });
    return session;
}

#pragma mark 文件下载
-(void)downloadFile{
    _fileName=@"1.mp4";
    NSString *urlStr=[NSString stringWithFormat: @"http://192.168.1.208/FileDownload.aspx?file=%@",_fileName];
    urlStr =[urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url=[NSURL URLWithString:urlStr];
    NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:url];
    
    //后台会话
    _downloadTask=[[self backgroundSession] downloadTaskWithRequest:request];
    
    [_downloadTask resume];
}
#pragma mark - 下载任务代理
#pragma mark 下载中(会多次调用,可以记录下载进度)
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
//    [NSThread sleepForTimeInterval:0.5];
//    NSLog(@"%.2f",(double)totalBytesWritten/totalBytesExpectedToWrite);
}

#pragma mark 下载完成
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
    NSError *error;
    NSString *cachePath=[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    NSString *savePath=[cachePath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@",[NSDate date]]];
    NSLog(@"%@",savePath);
    NSURL *saveUrl=[NSURL fileURLWithPath:savePath];
    [[NSFileManager defaultManager] copyItemAtURL:location toURL:saveUrl error:&error];
    if (error) {
        NSLog(@"didFinishDownloadingToURL:Error is %@",error.localizedDescription);
    }
}

#pragma mark 任务完成,不管是否下载成功
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
    if (error) {
        NSLog(@"DidCompleteWithError:Error is %@",error.localizedDescription);
    }
}
@end

运行上面的程序会发现即使程序退出到后台也能正常完成文件下载。为了提高用户体验,通常会在下载时设置文件下载进度,但是通过前面的介绍可以知道:当程序进入后台后,事实上任务是交给iOS系统来调度的,具体什么时候下载完成就不得而知,例如有个较大的文件经过一个小时下载完了,正常打开应用程序看到的此文件下载进度应该在100%的位置,但是由于程序已经在后台无法更新程序UI,而此时可以通过应用程序代理方法进行UI更新。具体原理如下图所示: image.png

当NSURLSession在后台开启几个任务之后,如果有其中几个任务完成后系统会调用此应用程序的**-(void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler代理方法;此方法会包含一个competionHandler(此操作表示应用完成所有处理工作),通常我们会保存此对象;直到最后一个任务完成,此时会重新通过会话标识(上面sessionConfig中设置的)找到对应的会话并调用NSURLSession的-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session**代理方法,在这个方法中通常可以进行UI更新,并调用completionHandler通知系统已经完成所有操作。具体两个方法代码示例如下:

-(void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler{
    
    //backgroundSessionCompletionHandler是自定义的一个属性
    self.backgroundSessionCompletionHandler=completionHandler;
   
}

-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session{
    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    
    //Other Operation....
    
    if (appDelegate.backgroundSessionCompletionHandler) {
        
        void (^completionHandler)() = appDelegate.backgroundSessionCompletionHandler;
        
        appDelegate.backgroundSessionCompletionHandler = nil;
        
        completionHandler();
        
    }
}

NSURLConnection和NSURLSession的区别

1,使用现状

NSURLSession是NSURLConnection的替代者,在2013年苹果全球开发者大会上(WWDC2013)随iOS7一起发布的,NSURLSession是对NSURLConnection进行了重构优化后的新的网络接口。

,下载任务方式

NSURLConnection下载文件时,先是将整个文件下载到内存,然后再写入到沙盒,如果文件比较大,就会出现内存暴涨的情况。

而使用NSURLSessionDownloadTask下载文件会默认下载到沙盒中的temp文件中,不会出现内存暴涨的情况,但是在下载完成后会把tem中的临时文件删除,所以需要在初始化任务方法时,在completionHandler回调中增加保存文件的代码。

,请求方法的控制

NSURLSession有三个控制方法,取消(cancel)、暂停(suspend)、继续(resume),暂停以后可以恢复当前的请求任务。

NSURLConnection没有暂停的方法,只有start,cancel方法,cancel可以停止请求的发送,停止后不能继续访问,需要创建新的请求。

4,断点续传的方式

NSURLConnection进行断点下载,通过设置请求的HTTPHeaderField的Range属性,开启运行循环,

NSURLSession进行断点下载,当暂停下载任务后,如果downloadTask(下载任务)为非空,调用cancelByProducingResumeData:(void (^)(NSData *resumeData))completionHandler这个方法,这个方法接收一个参数,完成处理代码块,这个代码块有一个NSData参数resumeData,如果resumeData非空,我们就保存这个对象到视图控制器的resumeData属性中,在点击再次下载时,通过调用[ [self.session downloadTaskWithResumeData:self.resumeData]resume]方法进行继续下载操作

经过以上比较可以发现,使用NSURLSession进行断点下载更加便捷.

,配置信息

NSURLSession的构造方法(sessionWithConfiguration:delegate:delegateQueue)中有一个NSURLSessionConfiguration类的参数可以设置配置信息,其决定了cookie,安全和缓存策略,最大主机连接数,资源管理,网络超时等配置。NSURLConnection不能进行这个配置,相比较于NSURLConnection依赖一个全局的配置对象,缺乏灵活性而言,NSURLSession有很大的改进了。(关于配置信息,后面会讲解到)

NSURLSession可以设置三种配置信息,分别通过调用三个类方法返回配置对象:

+ (NSURLSessionConfiguration *)defaultSessionConfiguration,配置信息使用基于硬盘的持久化缓存,保存用户的证书到钥匙串,使用共享cookie存储;

+ (NSURLSessionConfiguration *)ephemeralSessionConfiguration ,配置信息和default大致相同。但不会把cache、证书、以及任何和Session相关的数据存储到硬盘,而是存储在内存中,生命周期和Session一致。比如浏览器无痕浏览等功能就可以基于这个来做;

+ (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier,配置信息可以创建一个可以在后台甚至APP已经关闭的时候仍然在传输数据的session。注意,后台Session一定要在创建的时候赋予一个唯一的identifier,这样在APP下次运行的时候,能够根据identifier来进行相关的区分。如果用户关闭了APP,IOS 系统会关闭所有的background Session。而且被用户强制关闭了以后,IOS系统不会主动唤醒APP,只有用户下次启动了APP,数据传输才会继续

其中几点和NSURLConnetion相似:

Cookie 策略

HTTPCookieStorage存储了 session 所使用的 cookie。默认情况下会使用 NSHTTPCookieShorage的 +sharedHTTPCookieStorage这个单例对象,这与 NSURLConnection是相同的。

HTTPCookieAcceptPolicy决定了什么情况下 session 应该接受从服务器发出的 cookie。

HTTPShouldSetCookies指定了请求是否应该使用 session 存储的 cookie,即 HTTPCookieSorage属性的值。

安全策略

URLCredentialStorage存储了 session 所使用的证书。默认情况下会使用 NSURLCredentialStorage的 +sharedCredentialStorage这个单例对象,这与 NSURLConnection是相同的。TLSMaximumSupportedProtocol

和 TLSMinimumSupportedProtocol

确定 session 是否支持 SSL 协议

缓存策略

URLCache是 session 使用的缓存。默认情况下会使用 NSURLCache的 +sharedURLCache这个单例对象,这与 NSURLConnection是相同的。requestCachePolicy指定了一个请求的缓存响应应该在什么时候返回。这相当于 NSURLRequest的 -cachePolicy方法。