网络编程—NSURLSession

网络编程—NSURLSession_第1张图片
文艺求关注.png

okay,NSURLConnection在iOS9.0之后已经被废弃掉了,当然我们在开发中不免会遇到一些NSURLConnection的代码,到时候知道如何处理就Ok了,我们的重点是要好好聊心啊NSURLSession

NSURLSession

  • 使用步骤:
    • 使用NSURLSession对象创建Task,然后执行Task
    • Task的类型


      网络编程—NSURLSession_第2张图片
      Task的类型.png

NSURLSessionDataTask

  • 使用NSURLSession比NSURLConnection多几个步骤

1.发送GET请求

- (void)sessionSendRequestWithGet {

    // 01.创建请求路径
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520it&type=JSON"];
    
    // 02.创建请求对象
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    // 03.创建会话对象(单例模式获取,还有一种方法创建会话对象:自定义Session,等下会讲)
    NSURLSession *session = [NSURLSession sharedSession];
    
    /**
     // 04.创建Task
     
     @param NSURL 请求对象
     @param completionHandler 当请求完成的时候调用
        data:响应体信息
        response:响应头信息
        error:错误信息当请求失败的时候 error有值
     */
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        NSLog(@"-----%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
    }];
    // 05.执行Task
    [dataTask resume];
}

- (void)dealloc {
    // 清理方法
    [self.session invalidateAndCancel];
}
  • *注意:04创建dataTask的时候还有一种简单方法(不需要设置请求对象,直接传URL)的方法
    //*注意:dataTaskWithURL 内部会自动的将请求路径作为参数创建一个请求对象(即不可变只能发GET请求)
    NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        NSLog(@"-----%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
    }];

2.发送POST请求

- (void)sessionSendRequestWithPost {

    // 01.确定URL
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login"];
    // 02.创建可变的请求对象
    NSMutableURLRequest *mutableRequest = [NSMutableURLRequest requestWithURL:url];
    
    // 2.1设置请求方式为POST
    mutableRequest.HTTPMethod = @"POST";
    
    // 2.2设置请求体
    mutableRequest.HTTPBody = [@"username=123&pwd=123&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];
    // 03.创建会话对象
    NSURLSession *session = [NSURLSession sharedSession];
    
    // 04.创建Task
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:mutableRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        //该Block在子线程中调用,
        NSLog(@"%@", [NSThread currentThread]);
        
        // 06.解析数据
        NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
    }];
    // 05.执行Task
    [dataTask resume];
}

- (void)dealloc {
    // 清理方法
    [self.session invalidateAndCancel];
}

3.NSURLSession的代理方法

- (void)sessionUsedWithDelegate {

    // 01.确定URL
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=123&pwd=123&type=JSON"];
    
    // 02.创建请求对象
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    /**
     // 03.创建会话对象(使用代理方法)
     @param NSURLSessionConfiguration 配置信息
     @param NSURLSessionDelegate 代理
     @param NSOperationQueue 设置代理在哪个线程中调用
     */
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    
    // 04.创建Task
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
    
    // 05.执行task
    [dataTask resume];
}
@property (nonatomic, strong) NSString *fullPath;
@property (nonatomic, strong) NSFileHandle *fileHandle;
@property (nonatomic, assign) NSInteger totalSize;
@property (nonatomic, assign) NSInteger currentSize;

@property (weak, nonatomic) IBOutlet UIProgressView *progressView;  // 显示文件下载进度
#pragma mark - NSURLSessionDataDelegate
/**
 // 接收到服务器的响应时调用 它默认会取消该请求
 @param session 会话信息
 @param dataTask 请求任务
 @param response 响应头信息
 @param completionHandler 回调 传给系统的
 */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
    // 获得文件的总大小
    self.totalSize = response.expectedContentLength;
    
    //1.获得文件路径
    self.fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];
    
    // 创建一个空的文件
    [[NSFileManager defaultManager] createFileAtPath:self.fullPath contents:nil attributes:nil];
    
    // 创建文件句柄
    self.fileHandle = [NSFileHandle fileHandleForWritingAtPath:self.fullPath];
    NSLog(@"%s", __func__);
    /**
     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 {

    NSLog(@"%s", __func__);
    
    // 写入数据
    [self.fileHandle writeData:data];
    
    // 计算文件的下载进度
    self.currentSize += data.length;
    NSLog(@"%f", 1.0 * self.currentSize / self.totalSize);
    self.progressView.progress = 1.0 * self.currentSize / self.totalSize;

}
/**
 // 请求结束或者失败的时候调用该方法,
 @param session 会话对象
 @param task 请求任务
 @param error 错误信息
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {

    NSLog(@"%s", __func__);
    
    // 关闭文件句柄
    [self.fileHandle closeFile];
    self.fileHandle = nil;
}

- (void)dealloc {
    // 清理方法
    [self.session invalidateAndCancel];
}

NSURLSessionDownloadTask

  • downloadTask文件下载(优点:无需担心内存问题—子线程完成,缺点,无法监听下载进度)
- (void)downloadWithDownloadTask {
    
    // 01.确定路径
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_02.png"];
    
    // 02.创建请求对象
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    // 03.创建会话对象
    NSURLSession *session = [NSURLSession sharedSession];
    /**
     // 04.创建下载任务(downloadTask)

     @param NSURLRequest 请求对象
     @param completionHandler 回调
        location: 文件保存临时沙盒路径
        response: 响应头信息
        error: 错误信息
     */
    // 注意:该方法内部已经实现了遍下载数据,遍写入沙盒(tmp)的操作,
    // 缺点:无法监听下载进度
    NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        // 06.解析数据
        NSLog(@"%@------%@---", location, [NSThread currentThread]);  // 子线程中完成
        // 6.1拼接文件的全路径
        // 方法一:
        NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:url.lastPathComponent]; //url.lastPathComponent: 获得URL最后的字节为为文件的名称

        // 方法二:
        NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];
        // 6.2剪切文件
        [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil];
    }];
    
    // 05.执行下载任务
    [downloadTask resume];
}
  • downloadTask通过代理实现文件下载(可监听文件下载进度)
- (void)downloadTaskWithDelegate {
    
    // 01.确定路径
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_02.png"];
    
    // 02.创建请求对象
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    // 03.创建会话对象并设置代理
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    // 04.创建downloadTask
    NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request];
    // 05.执行下载任务
    [downloadTask resume];  
}


#pragma mark - NSURLSessionDownloadDelegate
/**
 写数据
 @param session 会话对象
 @param downloadTask 下载任务
 @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 {
    
    // 1.获得文件的下载进度
    NSLog(@"%f", 1.0 * totalBytesWritten / totalBytesExpectedToWrite);

}
/**
 当恢复下载的时候调用
 @param session 会话对象
 @param downloadTask 下载任务
 @param fileOffset 从什么地方开始下载
 @param expectedTotalBytes 文件总大小
 */
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes {

    NSLog(@"%zd", __func__);
}
/**
 当下载完成的时候调用
 @param session 会话对象
 @param downloadTask 下载任务
 @param location 文件临时存储路径
 */
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {

    NSLog(@"%@", location);
    
    // 1.拼接文件的全路径
    NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
    
    // 2.剪切文件
    [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil];
}
/**
 请求结束调用
 @param session 会话对象
 @param task 下载任务
 @param error 错误信息
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {

    NSLog(@"didCompleteWithError");
}

- (void)dealloc {

    // 清理方法一
    [self.session finishTasksAndInvalidate];
}

需求:如何使用NSURLSessionDataTask实现断点离线续传下载,

@property (nonatomic, strong) NSURLSessionDataTask *dataTask;
@property (nonatomic, assign) NSInteger currentSize;
#pragma mark - lazy load
- (NSURLSessionDataTask *)dataTask {

    if (_dataTask == nil) {
        // 01.确定URL
        NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_05.mp4"];
        
        // 02.创建请求对象
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
        
        // 2.1设置请求头信息,告诉服务器请求哪一部分数据
        self.currentSize = [self getFileSize];
        //设置请求的数据范围
        /*
         bytes=0-100
         bytes=500-1000
         bytes=-100 请求文件的前100个字节
         bytes=500-
         */
        NSString *range = [NSString stringWithFormat:@"bytes=%zd-", self.currentSize];
        [request setValue:range forHTTPHeaderField:@"Range"];
        
        // 04.创建DataTask任务
        _dataTask = [self.session dataTaskWithRequest:request];
    }
    return _dataTask;
}
@property (nonatomic, strong) NSDictionary *fileInfoDic;
- (NSInteger) getFileSize {
    // 2.1获得指定文件路径对应的文件数据大小
    self.fileInfoDic = [[NSFileManager defaultManager] attributesOfItemAtPath:self.fullPath error:nil];
    NSLog(@"%@", self.fileInfoDic);
    NSInteger currentSize = [self.fileInfoDic[@"NSFileSize"] integerValue];
    return currentSize;
}
@property (nonatomic, strong) NSString *fullPath;
#pragma mark - lazy load
- (NSString *)fullPath {
    
    if (_fullPath == nil) {
        
        // 01.获得文件的全路径
        _fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:FileName];
    }
    return _fullPath;
}
@property (nonatomic, strong) NSURLSession *session;
#pragma mark - lazy load
- (NSURLSession *)session {

    if (_session == nil) {
        
        // 03.创建会话对象
        _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    }
    return _session;
}
// 在storyboard中添加按钮,分别命名:开始下载、暂停下载、继续下载、取消下载,并拖线

#pragma mark - method
- (IBAction)startDownloadBtnClick:(id)sender {
    
    NSLog(@"+++++++++++++++++++++++ start +++");
    // 执行dataTask
    [self.dataTask resume];
}
- (IBAction)suspendDownloadBtnClick:(id)sender {
    
    NSLog(@"+++++++++++++++++++++++ suspend +++");
    [self.dataTask suspend];
}
- (IBAction)continueDownloadBtnClick:(id)sender {
    
    NSLog(@"+++++++++++++++++++++++ continue +++");
    [self.dataTask resume];
}
- (IBAction)cancelDownloadBtnClick:(id)sender {
    
    NSLog(@"+++++++++++++++++++++++ cancel +++");
    // 此取消不可以恢复
    [self.dataTask cancel];
    self.dataTask = nil;
}
#pragma mark - property
@property (weak, nonatomic) IBOutlet UIProgressView *progerssView;  //进度条
@property (nonatomic, assign) NSInteger totalSize;
@property (nonatomic, strong) NSString *filePath;
@property (nonatomic, strong) NSFileHandle *fileHandle;

#pragma mark - NSURLSessionDataDelegate
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {

    // *1.获得文件的总大小 本次请求数据的大小
    self.totalSize = response.expectedContentLength + self.currentSize;
   
    // - 01/ 将文件总大小写入到磁盘
    [[[NSString stringWithFormat:@"%zd", self.totalSize] dataUsingEncoding:NSUTF8StringEncoding] writeToFile:SizeOfFullPath atomically:YES];
    
   
    if (self.currentSize == 0) {
        // 02.创建一个空的文件
        [[NSFileManager defaultManager] createFileAtPath:self.fullPath contents:nil attributes:nil];
    }
    
    // 03.创建文件句柄
    self.fileHandle = [NSFileHandle fileHandleForWritingAtPath:self.fullPath];
    [self.fileHandle seekToEndOfFile];  //移动文件句柄到文件末尾
    
    completionHandler(NSURLSessionResponseAllow);
}

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

    // 04.写入数据
    [self.fileHandle writeData:data];
    
    // *2.计算下载进度
    self.currentSize += data.length;
    NSLog(@"%f", 1.0 * self.currentSize / self.totalSize);
    self.progerssView.progress = 1.0 * self.currentSize / self.totalSize;
}

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

    // 05.关闭文件句柄
    [self.fileHandle closeFile];
    self.fileHandle = nil;
    NSLog(@"%@", self.fullPath);
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // - 02/ 获得之前已经下载的文件数据大小 => 获得沙盒中已经存在的数据大小
    // 获得某个路径对象的属性
    self.fileInfoDic = [[NSFileManager defaultManager] attributesOfItemAtPath:self.fullPath error:nil];
    
    self.currentSize = [self.fileInfoDic fileSize];
    
    NSLog(@"之前已经下载的数据大小:%zd", self.currentSize);
    
    // - 03/ 显示文件的进度信息 = 已经下载文件数据大小(self.currentSize)/ 文件总大小
    NSData *totalData = [NSData dataWithContentsOfFile:SizeOfFullPath];
    self.totalSize = [[[NSString alloc] initWithData:totalData encoding:NSUTF8StringEncoding] integerValue];
    
    // - 04/ 判断当前文件大小是否为0
    if (self.totalSize != 0) {
        self.progerssView.progress = 1.0 * self.currentSize / self.totalSize;
    }  
}

- (void)dealloc {

    // 清理方法
    [self.session invalidateAndCancel];
}

NSURLSession对象的释放

与NSURLConnection不一样的地方,NSURLSession在不用的时候需要手动将session对象释放

- (void)dealloc {

    // 清理方法一
    [self.session finishTasksAndInvalidate];

    // 清理方法二
    [self.session invalidateAndCancel];
}

使用NSURLSession完成上传任务

- (void)uploadWithSession02 {
    
    // 01确定URL
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/upload"];
    
    // 02创建可变的请求对象
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    
    // 2.1设置请求方法
    request.HTTPMethod = @"POST";
    
    // 2.2设置请求头信息
    //+ "设置请求头信息 Content-Type multipart/form-data; boundary=----WebKitFormBoundaryhGFJfxbHklxi7PXJ
    NSString *headerString = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",Kboundary];
    [request setValue:headerString forHTTPHeaderField:@"Content-Type"];
 
    /**
     // 04创建uploadTask
     @param NSURLRequest 请求对象
     @param NSURLResponse 传递上传的数据(请求体)
     */
    NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:[self getBodyData] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        // 06.解析
        NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);      
    }];
    
    // 05执行uploadTask
    [uploadTask resume];
}
@property (nonatomic, strong) NSURLSession *session;
// 在开发中会将session抽出来,懒加载同时设置配置信息
- (NSURLSession *)session {
    if (_session == nil) {
        // 03.设置会话对象
        NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration  defaultSessionConfiguration];
        _session = [NSURLSession sessionWithConfiguration: configuration delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    }
    return _session;
}
// 拼接请求体信息,与NSURLConnection一样,上传文件的时候都需要设置请求头和请求体信息
-(NSData *)getBodyData
{
    NSMutableData *fileData = [NSMutableData data];
    
    //① 文件参数
    /*
     --分隔符
     Content-Disposition: form-data; name="file"; filename="Snip20161012_16.png"
     Content-Type: image/png
     空行
     图片的二进制数据
     */
    [fileData appendData:[[NSString stringWithFormat:@"--%@",Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    //name=file        参数(固定的 服务器端规定)
    //filename=123.png 该文件上传到服务器后以什么名称保存
    [fileData appendData:[@"Content-Disposition: form-data; name=\"file\"; filename=\"Sss.png\"" dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    
    //Content-Type 上传给服务器的文件的数据类型(MIMEType)
    [fileData appendData:[@"Content-Type: image/png" dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    [fileData appendData:KNewLine];
    NSData *data = [NSData dataWithContentsOfFile:@"/Users/Vincent/Desktop/3.pic"];
    [fileData appendData:data];
    [fileData appendData:KNewLine];
    
    
    //②非文件参数
    /*
     --分隔符
     Content-Disposition: form-data; name="username"
     空行
     xiaoming
     */
    [fileData appendData:[[NSString stringWithFormat:@"--%@",Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    //name=username 参数名 usernmae|pwd
    [fileData appendData:[@"Content-Disposition: form-data; name=\"username\"" dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    [fileData appendData:KNewLine];
    [fileData appendData:[@"xiaomingHeXiaohong" dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    
    //③ 结尾标志
    /*
     --分隔符--
     */
    [fileData appendData:[[NSString stringWithFormat:@"--%@--",Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];
    
    return fileData;
}

#pragma mark - NSURLSessionDataDelegate
/**
 @param session 会话对象
 @param task 上传任务
 @param bytesSent 表示本次上传的数据
 @param totalBytesSent 上传完成数据的大小
 @param totalBytesExpectedToSend 文件的总大小
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend {
    
    // 监听下载进度
    NSLog(@"%f", 1.0 * totalBytesSent / totalBytesExpectedToSend);
}

网络编程—NSURLSession_第3张图片
关注一下又不会怀孕.png

你可能感兴趣的:(网络编程—NSURLSession)