NSURLConnetion与NSURLSession的区别

相同点:

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

  • 1、比如进行普通的Get/Post请求
    说明:任何NSURLRequest默认都是get请求。

    • (1)创建一个NSURL对象,设置请求路径(设置请求路径)
    • (2)传入NSURL创建一个NSURLRequest对象,设置请求头和请求体(创建请求对象
    • (3)使用NSURLConnection发送NSURLRequest(发送请求)
NSURLConnetion:

方法1:NSURLConnetion通过类方法直接发送request,通过闭包处理异步操作

   - (void)ConnetionPost {
       NSString *username = self.usernameText.text;
       NSString *pwd = [self base64Encode:self.pwdText.text];
       NSString *urlString = @"http://10.0.1.7/login.php";
       urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
       NSURL *url = [NSURL URLWithString:urlString];
       NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
       request.HTTPMethod = @"POST";
       NSString *bodyString = [NSString stringWithFormat:@"username=%@&password=%@", username, pwd];
   request.HTTPBody = [bodyString dataUsingEncoding:NSUTF8StringEncoding];

       // 同步请求,代码会阻塞在这里一直等待服务器返回,如果data为nil则请求失败,当获取少量数据时可以使用此方法。
       // sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse * _Nullable * _Nullable)response error:(NSError **)error

       // 注意,block的执行线程为queue,如果block涉及到UI操作,则必须回到主线程:[NSOperationQueue mainQueue]
       [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
       
       NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
       
       // 数据处理代码...
   }];
}

方法2:获取NSURLConnetion对立对象,将对象加入到runloop,通过delegate回调获取数据

    //创建连接有三个方法需要了解一下
    // 该方法是NSURLConnection的默认构造函数,startImmediately参数,如果为YES,代表会将当前的connection实例加入到当前的runloop中,该connection的delegate的回调方法都会在当前线程执行,自动实现调度,所以这种情况下甚至是不需要调用 -start方法来开始请求;
    //如果为NO,则需要手动调度,将当前的connection加入到一个线程的runloop中(如果不添加,默认会添加到当前线程的runloop中)。
    - (nullable instancetype)initWithRequest:(NSURLRequest *)request delegate:(nullable id)delegate startImmediately:(BOOL)startImmediately  startImmediately;

    //实质为调用用的[self initWithRequest:request delegate:delegate startImmediately:YES];
    - (nullable instancetype)initWithRequest:(NSURLRequest *)request delegate:(nullable id)delegate ;

    //类方法,不需要手动调用[connection start],加入到当前的Runloop
    + (NSURLConnection*)connectionWithRequest:(NSURLRequest *)request delegate:(id)delegate;
    self.connection = [NSURLConnection connectionWithRequest:self.request delegate:self];
    // 设置运行循环
    [self.connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
    // 设置代理工作队列
    [self.connection setDelegateQueue:[[NSOperationQueue alloc] init]];

使用代理模式需要实现NSURLConnectionDataDelegate协议,此协议提供了几个代理方法,涵盖了请求交互的几个步骤

//当接收到服务器响应时调用,response为响应头部
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;

//接收到服务返回的数据时调用,多次调用,直至接受到全部数据,每次接受一部分数据,放入到data中
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;

//数据接收完成是调用
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;

//监控上传数据的进度,再上传数据时调用
- (void)connection:(NSURLConnection *)connection   didSendBodyData:(NSInteger)bytesWritten
                                                 totalBytesWritten:(NSInteger)totalBytesWritten
                                         totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite;

//请求错误(失败)的时候调用
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;

NSURLSession:
- (void)SessionPost {
    // 苹果直接提供了一个全局的session
    NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:[self request] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        // 处理数据
    }];
    // 需要把任务开始。 默认都是挂起
    [task resume];
}

不同点:

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

二、 下载任务方式
NSURLConnection下载文件时,先将整个文件下载到内存,然后再写入沙盒,如果文件比较大,就会出现内存暴涨的情况。而使用NSURLSessionUploadTask下载文件,会默认下载到沙盒中的tem文件夹中,不会出现内存暴涨的情况,但在下载完成后会将tem中的临时文件删除,需要在初始化任务方法时,在completionHandler回调中增加保存文件的代码。
具体差别还可以分为以下几个部分:

NSURLConnettion下载主要问题:

  • 1、没有办法直接跟踪到下载的进度
  • 2、会出现内存峰值

首先建立下载的请求:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    NSString *urlString = @"http://dldir1.qq.com/invc/tt/QQBrowser_for_Mac.dmg";
    urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url = [NSURL URLWithString:urlString];
    NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:10.0];
    // NSURLRequestReloadIgnoringLocalCacheData  忽略本地的缓存数据
    self.conn = [NSURLConnection connectionWithRequest:request delegate:self];
    
    // 设置运行循环
    [self.conn scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
    // 设置代理工作队列,也就是代理回调会在子线程上进行
    [self.conn setDelegateQueue:[[NSOperationQueue alloc] init]];
}

- (void)writeToSandbox:(NSData *)data {
    NSFileHandle *fp = [NSFileHandle fileHandleForWritingAtPath:self.targetPath];
    
    if (fp == nil) {
        [data writeToFile:self.targetPath atomically:YES];
    } else {
        [fp seekToEndOfFile];
        [fp writeData:data];
        [fp closeFile];
    }
}

delegate回调处理数据

// 1. 接收到服务器响应
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { 
    // 保存要下载的文件的二进制数据长度,一边做进度观察
    self.expectedContentLength = response.expectedContentLength;
    //  清空当前下载的长度
    self.currentLength = 0;
    
    self.targetPath = [@"/Users/mac/Desktop" stringByAppendingPathComponent:response.suggestedFilename];
    [[NSFileManager defaultManager] removeItemAtPath:self.targetPath error:NULL];
}

// 2. 接收到服务器数据
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {    
    // 1> 计算下载进度
    self.currentLength += data.length;
    float progress = (float) self.currentLength / self.expectedContentLength;
    NSLog(@"%f %@", progress, [NSThread currentThread]);
    
    dispatch_async(dispatch_get_main_queue(), ^{
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate date]];
        self.progressView.progress = progress;
    });
    
    // 2> 拼接文件数据
    [self writeToSandbox:data];
}

解决办法:

  • 1、在- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;方法里面根据响应头返回缓存下来,然后在- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;每次接受的数据的时候用属性currentLength保存已经下载的数据大小和currentLength比较进行进度跟踪。
  • 2、如果采用sendAsynchronousRequest:queue:completionHandler:方法进行下载,只有下载完了completionHandler返回整个文件的NSData大小,会导致内存峰值飙升;解决此问题可以采用delegate的回调方法- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;每次接收到数据就写在硬盘上来避免。

三、断点续传的方式

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

  • 关键代码:
// 设置请求头信息,说明只需要请求该资源嗯一部分数据
    /*
     bytes=0-1000   表示下载0-1000的数据
     bytes=0-       表示从0开始下载到下载完毕
     bytes=100-     表示从100开始下载到下载完毕
     */
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    NSString *range = [NSString stringWithFormat:@"bytes=%zd-", self.currentSize];
    [request setValue:range forHTTPHeaderField:@"Range"];

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

四、请求方法的控制
1、NSURLConnection实例化对象,实例化开始,默认请求就发送(同步发送),不需要调用start方法。而cancel 可以停止请求的发送,停止后不能继续访问,需要创建新的请求。

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

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

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

+ (NSURLSessionConfiguration *)defaultSessionConfiguration,配置信息使用基于硬盘的持久话Cache,保存用户的证书到钥匙串,使用共享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方法。

具体可以参考从 NSURLConnection 到 NSURLSession

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容

  • iOS开发系列--网络开发 概览 大部分应用程序都或多或少会牵扯到网络开发,例如说新浪微博、微信等,这些应用本身可...
    lichengjin阅读 3,648评论 2 7
  • NSURLSession 类及其相关类为下载内容提供了接口。这个 API 提供了一系列丰富的代理方法来支持授权,而...
    芳仔小脚印阅读 915评论 1 8
  • 在苹果彻底弃用NSURLConnection之后自己总结的一个网上的内容,加上自己写的小Demo,很多都是借鉴网络...
    付寒宇阅读 4,268评论 2 13
  • 文/瑾懿 在今天学习的思考里,我遇到这么一个困惑,即实际工作中我发现,我的“老好人性格”让我下意识在同时忙不过来时...
    Elaine瑾懿阅读 309评论 1 1
  • 上飞机时北京还是炎热的夏天,因为值机时选了靠窗的位置,飞机平飞阶段机舱壁是很凉的,因此中间去卫生间换了次衣服,等到...
    凝语娃娃阅读 198评论 0 0