iOS NSURLSession

iOS9.0之后,NSURLConnection被苹果官方弃用
而在iOS7.0之后推出的NSURLSession迎来了它独步江湖的时代
NSURLSession为HTTP数据传输提供了一系列接口,
并在异步处理上比NSURLConnection好很多。

下面先说NSURLSession的简单用法:

简单GET请求:

//NSSession简单演示
- (void)demo1{
    //1. NSURL
    NSURL *url = [NSURL URLWithString:@"http://liubaiqi.cn"];
    
    //2. NSURLSession -> 苹果提供了一个全局的单例,简化程序开发
    NSURLSession *session = [NSURLSession sharedSession];
    
    //3. NSURLSessionDataTask -> 在 NSURLSession 开发中,所有任务都是由会话发起的!
    // session 是负责管理所有网络任务的
    NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        //反序列化
        id result = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
        NSLog(@"%@",result);
    }];
    
    //4. 启动任务
    [task resume];
}

注:所有的task都要调用resume方法才会开始进行请求


简单POST请求:

POST比GET多一个request

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];

NSURLSession断点续传

下面一个demo通过
NSURLSessionDownloadDelegate代理方法
实现下载功能,并提供断点续传
一共有三个Button,
分别负责 “开始、暂停、继续”


#import "ViewController.h"
#import "Button.h"
@interface ViewController ()<NSURLSessionDownloadDelegate>

/* 全局的网络会话,管理所有的网络任务 */
@property(nonatomic,strong)NSURLSession *session;

@property(weak, nonatomic) IBOutlet Button *progressView;

// 下载任务
@property(nonatomic,strong)NSURLSessionDownloadTask *downloadTask;
//如果使用weak弱引用,不需要清楚 downloadTask,但是开发时不建议使用,自定义控件都应该使用强引用
//@property(nonatomic,weak)NSURLSessionDownloadTask *downloadTask;
// 续传数据
@property(nonatomic,strong)NSData *resumeData;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

/*
 取消会话的位置应该在哪?
 
 1> 下载完成
 demo:
        //完成任务  如果会话已经被设置成完成,就无法再次使用
        //Attempted to create a task in a session that hasbeen invalidated
                    [self.session finishTasksAndInvalidate];
        //清空session
                    self.session = nil;
 
 2> 视图控制器销毁前
        //取消会话
            [self.session invalidateAndCancel];
            self.session = nil;
 
 *****两种方式的对比
 第一种方法:可以保证文件“可能”完整被下载完
           这种方法会重复创建和销毁 session,会造成额外的开销
 第二种方法:只是在离开界面前,销毁session,相当开销会小
           缺点:如果一个文件没有下载完成,会直接被取消掉
 
 真正的解决方法:
 - 在网络访问中,应该将所有的网络访问操作,封装到一个方法中,由一个统一的单例来负责处理所有的网络事件
 - Session对代理(单例)进行强引用,单例本身就是一个静态实例,本身就不需要释放
 - AFN -> 需要建立一个AFN 管理器的单例,统一负责所有的网络事件处理
 */

//懒加载
-(NSURLSession *)session{
    if (_session == nil) {
        //config 提供了一个全局的网络环境配置,包括:身份认证,浏览器类型,cookie,缓存,超时时长...
        //一旦设置可以全局共享,替代 NSURLRequest 中的附加信息
        NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
        
        /*
         队列:
         - 下载本身是一步的,是NSURLSession 统一管理调度的
         - 代理工作的队列,指的是,当网络事件需要监听的时候,去执行方法所调度的队列
         
         参数队列:指定调度代理方法执行的队列,并不会影响到 session 本身的异步执行
         - nil 代理在异步多个线程执行
         - [[NSOperationQueue alloc] init] 和 nil 的执行效果是一样的
         
         如果希望代理在异步执行,直接使用nil就可以了
         
         - [NSOperationQueue mainQueue] 主队列
         */
        
        _session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
        /*Session 会对代理进行强引用,如果任务执行结束后,不取消 session,会出现内存漏洞*/
    }
    return _session;
}

-(void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    
    //取消会话
    [self.session invalidateAndCancel];
    self.session = nil;
}

-(void)dealloc{
    NSLog(@"我走了");
}


//开始下载
-(IBAction)start{
    //如果有任务下载 清空任务冲下
    if(self.resumeData!=nil){
        NSLog(@"没有暂停任务");
        _resumeData=nil;
    }
    
    NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/1.mp4"];
    
    NSLog(@"开始");
    
    //如果要跟进下载的进度,也需要监听,和 NSURLConnection 一样 都是使用delegate!
    //NSURLSession 如果要跟进进度,不能使用系统提供的全局 session 单例,sharedSession供全局使用,供所有应用使用
    //代理有一个特点:一对一,所以不能使用全局session单例
    
    //如果要跟进下载进度,不能使用块代码回调的方式
    self.downloadTask = [self.session downloadTaskWithURL:url];
    //启动下载任务
    [self.downloadTask resume];
}

//暂停下载
-(IBAction)pause{
    //如果任务已经被暂停,不应该能够再次被暂停
    //取消下载任务
    //- 所有的任务都是由session发起的,任务一旦发起,session会对任务进行强引用
    //- 一旦任务背取消,session就不再对任务进行强引用,ARC中,如果没有对象对某个对象强引用,会被立即释放
    [self.downloadTask cancelByProducingResumeData:^(NSData * resumeData) {
        //参数:
        //resumeData:续传的数据
        NSLog(@"数据长度%tu",resumeData.length);
        
        self.resumeData = resumeData;
        
        //释放了下载任务
        self.downloadTask = nil;
    }];
}

//继续下载
-(IBAction)resume{
    if(self.resumeData==nil){
        NSLog(@"没有暂停任务");
        return;
    }
    //所以下载任务都是由Session发起的
    //使用续传数据启动下载
    //续传数据的作用就是建立新的下载任务,一旦下载任务建立后,续传数据就没用了
    self.downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];
    
    //清空续传数据
    self.resumeData = nil;
    
    //所有任务默认都是挂起的
    [self.downloadTask resume];
}


#pragma mark - NSURLSessionDownloadDelegate 代理方法
/**
 在   iOS 7.0中,以下三个方法都是必须的,
 到了  iOS 8.0中,只有 下载完成方法是必须的
 
 如果需要支持 iOS 7,以下三个方法都要实现
 */
// 1.下载完成方法
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
    
    NSLog(@"完成 %@",location);
    
}

// 2.下载进度
/**
 1) session
 2) downloadTask                调用代理方法的下载任务
 3) bytesWritten                本次下载的字节数
 4) totalBytesWritten           已经下载的字节数
 5) totalBytesExpectedToWrite   期望下载的字节数->文件总大小
 */
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
    
    float progress = (float) totalBytesWritten/totalBytesExpectedToWrite;
    NSLog(@"%f %@",progress,[NSThread currentThread]);
    
    //主线程更新UI
    dispatch_async(dispatch_get_main_queue(), ^{
        self.progressView.progress = progress;
    });
}

// 3.下载续传数据
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes{
    
    //可以什么都不用写
}
@end

NSURLSession对内存异步处理的优化非常好
下载时,内存最高仅为33.7MB


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

推荐阅读更多精彩内容