NSURLSession用法

简单介绍

  • 关于task

    • NSURLSessionTask是一个抽象类,本身不能使用,只能使用它的子类

      • NSURLSessionDataTask
      • NSURLSessionUploadTask
      • NSURLSessionDownloadTask
  • 使用步骤

    • 使用NSURLSession创建task,然后执行task

发送get请求

  • get请求第一种方式

    //1.创建NSURLSession对象(可以获取单例对象)

    NSURLSession *session = [NSURLSession sharedSession];

    //2.根据NSURLSession对象创建一个Task

    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=ss&pwd=ss&type=JSON"];

    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    //方法参数说明

    /*

    注意:该block是在子线程中调用的,如果拿到数据之后要做一些UI刷新操作,那么需要回到主线程刷新

    第一个参数:需要发送的请求对象

    block:当请求结束拿到服务器响应的数据时调用block

    block-NSData:该请求的响应体

    block-NSURLResponse:存放本次请求的响应信息,响应头,真实类型为NSHTTPURLResponse

    block-NSErroe:请求错误信息

     */

   NSURLSessionDataTask * dataTask =  [session dataTaskWithRequest:request completionHandler:^(NSData * __nullable data, NSURLResponse * __nullable response, NSError * __nullable error) {

        //拿到响应头信息

        NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;

        //4.解析拿到的响应数据

        NSLog(@"%@\n%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding],res.allHeaderFields);

    }];

    //3.执行Task

    //注意:刚创建出来的task默认是挂起状态的,需要调用该方法来启动任务(执行任务)

    [dataTask resume];

  • 发送get请求的第二种方式

  //注意:该方法内部默认会把URL对象包装成一个NSURLRequest对象(默认是GET请求)

    //方法参数说明

    /*

    //第一个参数:发送请求的URL地址

    //block:当请求结束拿到服务器响应的数据时调用block

    //block-NSData:该请求的响应体

    //block-NSURLResponse:存放本次请求的响应信息,响应头,真实类型为NSHTTPURLResponse

    //block-NSErroe:请求错误信息

     */

- (nullable NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url completionHandler:(void (^)(NSData * __nullable data, NSURLResponse * __nullable response, NSError * __nullable error))completionHandler;

发送POST请求


        //1.创建NSURLSession对象(可以获取单例对象)

    NSURLSession *session = [NSURLSession sharedSession];

    //2.根据NSURLSession对象创建一个Task

    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login"];

    //创建一个请求对象,并设请求方法为POST,把参数放在请求体中传递

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

    request.HTTPMethod = @"POST";

    request.HTTPBody = [@"username=name&pwd=124&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];

    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * __nullable data, NSURLResponse * __nullable response, NSError * __nullable error) {

        //拿到响应头信息

        NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;

        //解析拿到的响应数据

        NSLog(@"%@\n%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding],res.allHeaderFields);

    }];

    //3.执行Task

    //注意:刚创建出来的task默认是挂起状态的,需要调用该方法来启动任务(执行任务)

    [dataTask resume];

NSURLSession下载文件-代理

  • 创建NSURLSession对象,设置代理(默认配置)

 //1.创建NSURLSession,并设置代理

    /*

     第一个参数:session对象的全局配置设置,一般使用默认配置就可以

     第二个参数:谁成为session对象的代理

     第三个参数:代理方法在哪个队列中执行(在哪个线程中调用),如果是主队列那么在主线程中执行,如果是非主队列,那么在子线程中执行

     */

    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];

  • 根据Session对象创建一个NSURLSessionDataTask任务(post和get选择)

//创建task

NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_01.png"];

//注意:如果要发送POST请求,那么请使用dataTaskWithRequest,设置一些请求头信息

NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url];

  • 执行任务(其它方法,如暂停、取消等)

    //启动task

    //[dataTask resume];

    //其它方法,如取消任务,暂停任务等

    //[dataTask cancel];

    //[dataTask suspend];

  • 遵守代理协议,实现代理方法(3个相关的代理方法)

/*

 1.当接收到服务器响应的时候调用

     session:发送请求的session对象

     dataTask:根据NSURLSession创建的task任务

     response:服务器响应信息(响应头)

     completionHandler:通过该block回调,告诉服务器端是否接收返回的数据

 */

-(void)URLSession:(nonnull NSURLSession *)session dataTask:(nonnull NSURLSessionDataTask *)dataTask didReceiveResponse:(nonnull NSURLResponse *)response completionHandler:(nonnull void (^)(NSURLSessionResponseDisposition))completionHandler

/*

 2.当接收到服务器返回的数据时调用

 该方法可能会被调用多次

 */

-(void)URLSession:(nonnull NSURLSession *)session dataTask:(nonnull NSURLSessionDataTask *)dataTask didReceiveData:(nonnull NSData *)data

/*

 3.当请求完成之后调用该方法

 不论是请求成功还是请求失败都调用该方法,如果请求失败,那么error对象有值,否则那么error对象为空

 */

-(void)URLSession:(nonnull NSURLSession *)session task:(nonnull NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error

  • 当接收到服务器响应的时候,告诉服务器接收数据(调用block)

//默认情况下,当接收到服务器响应之后,服务器认为客户端不需要接收数据,所以后面的代理方法不会调用

    //如果需要继续接收服务器返回的数据,那么需要调用block,并传入对应的策略

    /*

        NSURLSessionResponseCancel = 0, 取消任务

        NSURLSessionResponseAllow = 1,  接收任务

        NSURLSessionResponseBecomeDownload = 2, 转变成下载

        NSURLSessionResponseBecomeStream NS_ENUM_AVAILABLE(10_11, 9_0) = 3, 转变成流

    */

    completionHandler(NSURLSessionResponseAllow);

NSURLSessionDownloadTask实现大文件下载

  • 使用NSURLSession和NSURLSessionDownload可以很方便的实现文件下载操作

 /*

     第一个参数:要下载文件的url路径

     第二个参数:当接收完服务器返回的数据之后调用该block

     location:下载的文件的保存地址(默认是存储在沙盒中tmp文件夹下面,随时会被删除)

     response:服务器响应信息,响应头

     error:该请求的错误信息

     */

    //说明:downloadTaskWithURL方法已经实现了在下载文件数据的过程中边下载文件数据,边写入到沙盒文件的操作

    NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:url completionHandler:^(NSURL * __nullable location, NSURLResponse * __nullable response, NSError * __nullable error)

  • downloadTaskWithURL内部默认已经实现了变下载边写入操作,所以不用开发人员担心内存问题

  • 文件下载后默认保存在tmp文件目录,需要开发人员手动的剪切到合适的沙盒目录

  • 缺点:没有办法监控下载进度

使用NSURLSessionDownloadTask实现大文件下载-监听下载进度

  • 创建NSURLSession并设置代理,通过NSURLSessionDownloadTask并以代理的方式来完成大文件的下载

     //1.创建NSULRSession,设置代理

    self.session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];

    //2.创建task

    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];

    self.downloadTask = [self.session downloadTaskWithURL:url];

    //3.执行task

    [self.downloadTask resume];

  • 常用代理方法的说明

    /*

 1.当接收到下载数据的时候调用,可以在该方法中监听文件下载的进度

 该方法会被调用多次

 totalBytesWritten:已经写入到文件中的数据大小

 totalBytesExpectedToWrite:目前文件的总大小

 bytesWritten:本次下载的文件数据大小

 */

-(void)URLSession:(nonnull NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite

/*

 2.恢复下载的时候调用该方法

 fileOffset:恢复之后,要从文件的什么地方开发下载

 expectedTotalBytes:该文件数据的总大小

 */

-(void)URLSession:(nonnull NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes

/*

 3.下载完成之后调用该方法

 */

-(void)URLSession:(nonnull NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(nonnull NSURL *)location

/*

 4.请求完成之后调用

 如果请求失败,那么error有值

 */

-(void)URLSession:(nonnull NSURLSession *)session task:(nonnull NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error

实现断点下载相关代码

  • 局限性
    • 如果用户点击暂停之后退出程序,那么需要把恢复下载的数据写一份到沙盒,代码复杂度更
    • 如果用户在下载中途未保存恢复下载数据即退出程序,则不具备可操作性

    //如果任务,取消了那么以后就不能恢复了

    //    [self.downloadTask cancel];

    //如果采取这种方式来取消任务,那么该方法会通过resumeData保存当前文件的下载信息

    //只要有了这份信息,以后就可以通过这些信息来恢复下载

    [self.downloadTask cancelByProducingResumeData:^(NSData * __nullable resumeData) {

        self.resumeData = resumeData;

    }];

    -----------

    //继续下载

    //首先通过之前保存的resumeData信息,创建一个下载任务

    self.downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];

     [self.downloadTask resume];

  • 计算当前下载进度

    //获取文件下载进度

    self.progress.progress = 1.0 * totalBytesWritten/totalBytesExpectedToWrite;

使用NSURLSessionDataTask实现大文件离线断点下载 (完整)

关于NSOutputStream的使用


    //1. 创建一个**输入流**,数据追加到文件的屁股上

    //把数据写入到指定的文件地址,如果当前文件不存在,则会自动创建

    NSOutputStream *stream = [[NSOutputStream alloc]initWithURL:[NSURL fileURLWithPath:[self fullPath]] append:YES];

    //2. 打开流

    [stream open];

    //3. 写入流数据

    [stream write:data.bytes maxLength:data.length];

    //4.当不需要的时候应该关闭流

    [stream close];

关于网络请求请求头的设置

  • 可以设置请求下载文件的某一部分

    //1. 设置请求对象

    //1.1 创建请求路径

    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];

    //1.2 创建可变请求对象

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

    //1.3 拿到当前文件的残留数据大小

    self.currentContentLength = [self FileSize];

    //1.4 告诉服务器从哪个地方开始下载文件数据

    NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentContentLength];

    NSLog(@"%@",range);

    //1.5 设置请求头

    [request setValue:range forHTTPHeaderField:@"Range"];

NSURLSession对象的释放


-(void)dealloc

{

    //在最后的时候应该把session释放,以免造成内存泄露

    //    NSURLSession设置过代理后,需要在最后(比如控制器销毁的时候)调用session的invalidateAndCancel或者resetWithCompletionHandler,才不会有内存泄露

    //    [self.session invalidateAndCancel];

    [self.session resetWithCompletionHandler:^{

        NSLog(@"释放---");

    }];

}

NSURLSession实现文件上传

  • 实现文件上传的方法

      /*

     第一个参数:请求对象

     第二个参数:请求体(要上传的文件数据)

     block回调:

     NSData:响应体

     NSURLResponse:响应头

     NSError:请求的错误信息

     */

    NSURLSessionUploadTask *uploadTask =  [session uploadTaskWithRequest:request fromData:data completionHandler:^(NSData * __nullable data, NSURLResponse * __nullable response, NSError * __nullable error)

  • 设置代理,在代理方法中监听文件上传进度

/*

 调用该方法上传文件数据

 如果文件数据很大,那么该方法会被调用多次

 参数说明:

     totalBytesSent:已经上传的文件数据的大小

     totalBytesExpectedToSend:文件的总大小

 */

-(void)URLSession:(nonnull NSURLSession *)session task:(nonnull NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend

{

    NSLog(@"%.2f",1.0 * totalBytesSent/totalBytesExpectedToSend);

}

  • 关于NSURLSessionConfiguration相关
  • 作用:可以统一配置NSURLSession,如请求超时等
  • 创建的方式和使用

//创建配置的三种方式

+ (NSURLSessionConfiguration *)defaultSessionConfiguration;

+ (NSURLSessionConfiguration *)ephemeralSessionConfiguration;

+ (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier NS_AVAILABLE(10_10, 8_0);

//统一配置NSURLSession

-(NSURLSession *)session

{

    if (_session == nil) {

        //创建NSURLSessionConfiguration

        NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];

        //设置请求超时为10秒钟

        config.timeoutIntervalForRequest = 10;

        //在蜂窝网络情况下是否继续请求(上传或下载)

        config.allowsCellularAccess = NO;

        _session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];

    }

    return _session;

}

离线断点下载全部代码

//

//  ViewController.m

//  05-掌握-NSURLSession相关代理方法

//

//  Created by sunhui on 16/2/26.

//  Copyright © 2016年 sunhui. All rights reserved.

//

#import "ViewController.h"

#define FileName @"121212.mp4"

@interface ViewController ()

@property (weak, nonatomic) IBOutlet UIProgressView *proessView;

/** 接受响应体信息 */

@property (nonatomic, strong) NSFileHandle *handle;

@property (nonatomic, assign) NSInteger totalSize;

@property (nonatomic, assign) NSInteger currentSize;

@property (nonatomic, strong) NSString *fullPath;

@property (nonatomic, strong)  NSURLSessionDataTask *dataTask;

@property (nonatomic, strong) NSURLSession *session;

@end

@implementation ViewController

-(void)viewDidLoad

{

    [super viewDidLoad];

    

    //1.读取保存的文件总大小的数据,0

    //2.获得当前已经下载的数据的大小

    //3.计算得到进度信息

    

}

-(NSString *)fullPath

{

    if (_fullPath == nil) {

        

        //获得文件全路径

        _fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:FileName];

    }

    return _fullPath;

}

-(NSURLSession *)session

{

    if (_session == nil) {

        //3.创建会话对象,设置代理

        /*

         第一个参数:配置信息 [NSURLSessionConfiguration defaultSessionConfiguration]

         第二个参数:代理

         第三个参数:设置代理方法在哪个线程中调用

         */

        _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];

    }

    return _session;

}

-(NSURLSessionDataTask *)dataTask

{

    if (_dataTask == nil) {

        //1.url

        NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];

        

        //2.创建请求对象

        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

        

        //3 设置请求头信息,告诉服务器请求那一部分数据

        self.currentSize = [self getFileSize];

        NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentSize];

        [request setValue:range forHTTPHeaderField:@"Range"];

        

        //4.创建Task

        _dataTask = [self.session dataTaskWithRequest:request];

    }

    return _dataTask;

}

-(NSInteger)getFileSize

{

    //获得指定文件路径对应文件的数据大小

    NSDictionary *fileInfoDict = [[NSFileManager defaultManager]attributesOfItemAtPath:self.fullPath error:nil];

    NSLog(@"%@",fileInfoDict);

    NSInteger currentSize = [fileInfoDict[@"NSFileSize"] integerValue];

    

    return currentSize;

}

- (IBAction)startBtnClick:(id)sender

{

    [self.dataTask resume];

}

- (IBAction)suspendBtnClick:(id)sender

{

    NSLog(@"_________________________suspend");

    [self.dataTask suspend];

}

//注意:dataTask的取消是不可以恢复的

- (IBAction)cancelBtnClick:(id)sender

{

      NSLog(@"_________________________cancel");

    [self.dataTask cancel];

    self.dataTask = nil;

}

- (IBAction)goOnBtnClick:(id)sender

{

      NSLog(@"_________________________resume");

    [self.dataTask resume];

}

#pragma mark ----------------------

#pragma mark NSURLSessionDataDelegate

/**

 *  1.接收到服务器的响应 它默认会取消该请求

 *

 *  @param session           会话对象

 *  @param dataTask          请求任务

 *  @param response          响应头信息

 *  @param completionHandler 回调 传给系统

 */

-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler

{

    //获得文件的总大小

    //expectedContentLength 本次请求的数据大小

    self.totalSize = response.expectedContentLength + self.currentSize;

    

    if (self.currentSize == 0) {

        //创建空的文件

        [[NSFileManager defaultManager]createFileAtPath:self.fullPath contents:nil attributes:nil];

        

    }

    //创建文件句柄

    self.handle = [NSFileHandle fileHandleForWritingAtPath:self.fullPath];

    

    //移动指针

    [self.handle seekToEndOfFile];

    

    /*

     NSURLSessionResponseCancel = 0,取消 默认

     NSURLSessionResponseAllow = 1, 接收

     NSURLSessionResponseBecomeDownload = 2, 变成下载任务

     NSURLSessionResponseBecomeStream        变成流

     */

    completionHandler(NSURLSessionResponseAllow);

}

/**

 *  接收到服务器返回的数据 调用多次

 *

 *  @param session           会话对象

 *  @param dataTask          请求任务

 *  @param data              本次下载的数据

 */

-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data

{

    

    //写入数据到文件

    [self.handle writeData:data];

    

    //计算文件的下载进度

    self.currentSize += data.length;

    NSLog(@"%f",1.0 * self.currentSize / self.totalSize);

    

    self.proessView.progress = 1.0 * self.currentSize / self.totalSize;

}

/**

 *  请求结束或者是失败的时候调用

 *

 *  @param session           会话对象

 *  @param dataTask          请求任务

 *  @param error             错误信息

 */

-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error

{

    NSLog(@"%@",self.fullPath);

    

    //关闭文件句柄

    [self.handle closeFile];

    self.handle = nil;

}

-(void)dealloc

{

    //清理工作

    //finishTasksAndInvalidate

    [self.session invalidateAndCancel];

}

@end

你可能感兴趣的:(NSURLSession用法)