iOS-NSURLSession与NSURLConnection区别

目录
  • 使用现状
  • 普通任务和上传
  • 下载任务方式
  • 请求方法的控制
  • 断点续传的方式
  • 配置信息
一 使用现状

NSURLSession是NSURLConnection 的替代者,在2013年苹果全球开发者大会(WWDC2013)随ios7一起发布,是对NSURLConnection进行了重构优化后的新的网络访问接口。从iOS9.0开始, NSURLConnection中发送请求的两个方法已过期(同步请求,异步请求),初始化网络连接(initWithRequest: delegate:)的方法也被设置为过期,系统不再推荐使用,建议使用NSURLSession发送网络请求。

  • 同步发送请求
// macos(10.3,10.11), ios(2.0,9.0), tvos(9.0,9.0)
+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request
                 returningResponse:(NSURLResponse **)response
                             error:(NSError **)error;
  • 异步发送请求
//  macos(10.7,10.11), ios(5.0,9.0), tvos(9.0,9.0)
+ (void)sendAsynchronousRequest:(NSURLRequest*) request
                          queue:(NSOperationQueue*) queue
              completionHandler:(void (^)(NSURLResponse*response, NSData*data, NSError* connectionError));
  • 初始化网络连接
// macos(10.5,10.11), ios(2.0,9.0), tvos(9.0,9.0)
- (instancetype)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately;

// macos(10.3,10.11), ios(2.0,9.0), tvos(9.0,9.0
- (instancetype)initWithRequest:(NSURLRequest *)request delegate:(id)delegate;
  • 简单使用
- (void)useConnection {
    // 1.请求路径
    NSURL *url = [NSURL URLWithString:@"http://rap2api.taobao.org/app/mock/163155/gaoshilist"];
    // 2.创建请求对象
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    // 3.异步发送请求
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse * response, NSData *data, NSError *connectionError) {
        NSLog(@"length:%lu",(unsigned long)data.length);
    }];
}
二 普通任务和上传

NSURLSession针对下载/上传等复杂的网络操作提供了专门的解决方案,针对普通上传下载分别对应三种不同的网络请求任务:NSURLSessionDataTask, NSURLSessionUploadTaskNSURLSessionDownloadTask.。创建的task都是挂起状态,需要resume才能执行。

  • 当服务器返回的数据较小时,NSURLSession与NSURLConnection执行普通任务的操作步骤没有区别。
  • 执行上传任务时,NSURLSession与NSURLConnection一样同样需要设置POST请求的请求体进行上传。

普通任务NSURLSessionDataTask实例代码

- (void)sessionDataTask {
    // 1.请求路径
    NSURL *url = [NSURL URLWithString:@"http://rap2api.taobao.org/app/mock/163155/gaoshilist"];
    // 2.创建请求对象
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    // 3.创建 session 对象
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    
    // 普通任务
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse * response, NSError *error) {
        if (error) {
            NSLog(@"NSURLSessionDataTaskerror:%@",error);
            return;
        }
        
        // 解析数据
        NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
        NSLog(@"NSURLSessionDataTaskdic:%@",dic);
        
        //5.解析数据
        NSLog(@"NSURLSessionDataTask:%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
    }];
    
    // 执行 task
    [dataTask resume];
}

执行结果

image.png

上传任务时,NSURLSession设置 POST 请求的请求体

- (void)sessionDataTaskPost {
    // 1.请求路径
    NSURL *url = [NSURL URLWithString:@"http://rap2api.taobao.org/app/mock/163155/fankui"];
    // 2.创建请求对象
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    // 设置 post 请求方式
    request.HTTPMethod = @"POST";
    // 设置请求体
    request.HTTPBody = [@"" dataUsingEncoding:NSUTF8StringEncoding];
    
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:queue];
    
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (error) {
            NSLog(@"NSURLSessionDataTaskerror:%@",error);
            return;
        }
        
        //5.解析数据
        NSLog(@"NSURLSessionDataTask:%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
    }];
    
    [dataTask resume];
}

执行结果


image.png
三 下载任务方式

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

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

NSURLConnection下载文件

  • NSURLConnection实例代码
- (void)downloadFile {
    // 1.创建下载路径
    NSURL *url = [NSURL URLWithString:@"http://dldir1.qq.com/qqfile/QQforMac/QQ_V5.4.0.dmg"];
    // 2.创建请求对象
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    // NSURLConnection发送异步Get请求,并实现相应的代理方法,该方法iOS9.0之后废除了。
    [NSURLConnection connectionWithRequest:request delegate:self];
}

#pragma mark - NSURLConnectionDataDelegate

// 接收到响应的时候:创建一个空的沙盒文件
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    NSLog(@"totalLength = %lld",response.expectedContentLength);
}

// 接收到具体数据:把数据写入沙盒文件中
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    NSLog(@"data length = %lu",(unsigned long)data.length);
}

// 下载完文件之后调用:关闭文件、清空长度
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    NSLog(@"下载完成");
}

打印结果

image.png
image.png

NSURLSessionDownloadTask下载文件

  • NSURLSessionDownloadTask实例代码
- (void)sessionDownloadTask {
    // 1.请求路径
    NSURL *url = [NSURL URLWithString:@"http://www.pptbz.com/pptpic/UploadFiles_6909/201203/2012031220134655.jpg"];
    // 2.创建 session 对象
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    
    // 下载 task
    NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
        // 获取沙盒的 caches 路径
        NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"img.jpg"];
        // 生成 url 路径
        NSURL *url = [NSURL fileURLWithPath:path];
        // 将文件保存到指定文件目录下
        [[NSFileManager defaultManager] moveItemAtURL:location toURL:url error:nil];
    }];
    
    [task resume];
}

执行结果 - 断点调试

  • 未保存图片之前,下载的资源在临时文件路径下
image.png
  • 将下载资源从临时路径移动到指定路径下
image.png
四 请求方法的控制
  1. NSURLConnection实例化对象,实例化开始,默认请求就发送(同步发送),不需要调用start方法。而cancel 可以停止请求的发送,停止后不能继续访问,需要创建新的请求。

  2. NSURLSession有三个控制方法,取消(cancel),暂停(suspend),继续(resume),暂停后可以通过继续恢复当前的请求任务。默认不发送请求,需要手动调用resume方法

- (void)cancel;
- (void)suspend;
- (void)resume;
五 断点续传的方式
5.1 NSURLConnection

NSURLConnection进行断点下载,通过设置访问请求的HTTPHeaderFieldRange属性,开启运行循环,NSURLConnection的代理方法作为运行循环的事件源,接收到下载数据时代理方法就会持续调用,并使用NSOutputStream管道流进行数据保存。

  • 实例代码
// 开始下载
- (void)tapDownload {
    if (self.conn) {    // 如果有正在进行中的,需要停止先
        [self tapCancel];
    }
    // 1.URL
    NSURL *url = [NSURL URLWithString:@"http://dldir1.qq.com/qqfile/QQforMac/QQ_V5.4.0.dmg"];
    
    // 2.请求
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    
    // 设置请求头
    NSString *range = [NSString stringWithFormat:@"bytes=%lld-", self.currentLength];
    [request setValue:range forHTTPHeaderField:@"Range"];
    
    // 3.下载(创建完conn对象后,会自动发起一个异步请求)
    self.conn = [NSURLConnection connectionWithRequest:request delegate:self];
}
5.2 NSURLSession

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

实例代码如下

  • 一些属性
/** downloadtask*/
@property(nonatomic,strong)NSURLSessionDownloadTask *downloadTask;
/** data*/
@property(nonatomic,strong)NSData *resumeData;
/** session*/
@property(nonatomic,strong)NSURLSession *session;
  • 开始下载和停止下载点击操作
#pragma mark - 断点续传

// 开始下载
- (void)tapDownload {
    // 1.URL
    NSURL *url = [NSURL URLWithString:@"http://dldir1.qq.com/qqfile/QQforMac/QQ_V5.4.0.dmg"];
    if (self.resumeData) {  // 之前已经下载过了
        self.downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];
    } else {
        self.session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        self.downloadTask = [self.session downloadTaskWithRequest:request];
    }
    
    [self.downloadTask resume];
}

// 取消下载
- (void)tapSuspend {
    if (self.downloadTask) {
        [self.downloadTask suspend];
        __weak typeof (self)weakSelf = self;
        [self.downloadTask cancelByProducingResumeData:^(NSData *resumeData) {
            NSLog(@"resumeData:%@",resumeData);
            weakSelf.resumeData = resumeData;
            weakSelf.downloadTask = nil;
        }];
    }
}
  • NSURLSessionDownloadDelegate回调中保存数据
#pragma mark - NSURLSessionDownloadDelegate

/**
 *  写入临时文件时调用
 *  @param bytesWritten              本次写入大小
 *  @param totalBytesWritten         已写入文件大小
 *  @param totalBytesExpectedToWrite 请求的总文件的大小
 */
- (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;
    dispatch_async(dispatch_get_main_queue(), ^{
        self.progressLbe.text = [NSString stringWithFormat:@"%.2f",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];
    NSLog(@"downloadTask 移动文件路径");
}
六 配置信息
  1. NSURLSession的构造方法sessionWithConfiguration:delegate:delegateQueue中有一个 NSURLSessionConfiguration类的参数可以设置配置信息,其决定了cookie,安全和高速缓存策略,最大主机连接数,资源管理,网络超时等配置。

  2. NSURLConnection不能进行这个配置,相比于 NSURLConnection 依赖于一个全局的配置对象,缺乏灵活性而言。

  3. 看看NSURLSessionConfiguration的三种配置方式

@property (class, readonly, strong) NSURLSessionConfiguration *defaultSessionConfiguration;
@property (class, readonly, strong) NSURLSessionConfiguration *ephemeralSessionConfiguration;
+ (NSURLSessionConfiguration *)backgroundSessionConfiguration:(NSString *)identifier;
  • defaultSessionConfiguration:配置信息使用基于硬盘的持久话Cache,保存用户的证书到钥匙串,使用共享cookie存储;
  • ephemeralSessionConfiguration:配置信息和default大致相同。除了,不会把cache,证书,或者任何和Session相关的数据存储到硬盘,而是存储在内存中,生命周期和Session一致。比如浏览器无痕浏览等功能就可以基于这个来做;
  • backgroundSessionConfigurationWithIdentifier::配置信息可以创建一个可以在后台甚至APP已经关闭的时候仍然在传输数据的session。

注意,后台Session一定要在创建的时候赋予一个唯一的identifier,这样在APP下次运行的时候,能够根据identifier来进行相关的区分。如果用户关闭了APP,IOS 系统会关闭所有的background Session。而且,被用户强制关闭了以后,IOS系统不会主动唤醒APP,只有用户下次启动了APP,数据传输才会继续。


本文参考
NSURLSession与NSURLConnection区别


更多相关文章参考
iOS-NSURLSession详解(附实战代码)
iOS-NSURLConnection使用详解

你可能感兴趣的:(iOS-NSURLSession与NSURLConnection区别)