NSURLSession
一、基本使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | -( void ) get { //1.确定URL NSURL *url = [NSURL URLWithString: @"http://120.25.226.186:32812/login?username=hello&pwd=world&type=JSON" ]; //2.创建请求对象 NSURLRequest *request =[NSURLRequest requestWithURL:url]; //3.创建会话对象 NSURLSession *session = [NSURLSession sharedSession]; //4.创建Task /* 第一个参数:请求对象 第二个参数:completionHandler 当请求完成之后调用 data:响应体信息 response:响应头信息 error:错误信息当请求失败的时候 error有值 */ NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { //5.解析数据 NSLog( @"%@" ,[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]); }]; //6.执行Task [dataTask resume]; } -( void )get2 { //1.确定URL NSURL *url = [NSURL URLWithString: @"http://120.25.226.186:32812/login?username=520it&pwd=520it&type=JSON" ]; //2.创建请求对象 //NSURLRequest *request =[NSURLRequest requestWithURL:url]; //3.创建会话对象 NSURLSession *session = [NSURLSession sharedSession]; //4.创建Task /* 第一个参数:请求路径 第二个参数:completionHandler 当请求完成之后调用 data:响应体信息 response:响应头信息 error:错误信息当请求失败的时候 error有值 注意:dataTaskWithURL 内部会自动的将请求路径作为参数创建一个请求对象(GET) */ NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { //6.解析数据 NSLog( @"%@" ,[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]); }]; //5.执行Task [dataTask resume]; } -( void )post { //1.确定URL NSURL *url = [NSURL URLWithString: @"http://120.25.226.186:32812/login" ]; //2.创建请求对象 NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL:url]; //2.1 设置请求方法为post request.HTTPMethod = @"POST" ; //2.2 设置请求体 request.HTTPBody = [ @"username=520it&pwd=520it&type=JSON" dataUsingEncoding:NSUTF8StringEncoding]; //3.创建会话对象 NSURLSession *session = [NSURLSession sharedSession]; //4.创建Task /* 第一个参数:请求对象 第二个参数:completionHandler 当请求完成之后调用 !!! 在子线程中调用 data:响应体信息 response:响应头信息 error:错误信息当请求失败的时候 error有值 */ NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { NSLog( @"%@" ,[NSThread currentThread]); //6.解析数据 NSLog( @"%@" ,[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]); }]; //5.执行Task [dataTask resume]; } |
二、NSURLSession代理方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | <NSURLSessionDataDelegate> /** 接受响应体信息 */ @property (nonatomic, strong) NSMutableData *fileData; { if (_fileData == nil) { _fileData = [NSMutableData data]; } return _fileData; } //请求 //1.url NSURL *url = [NSURL URLWithString: @"http://120.25.226.186:32812/login?username=123&pwd=123&type=JSON" ]; //2.创建请求对象 NSURLRequest *request = [NSURLRequest requestWithURL:url]; //3.创建会话对象,设置代理 /* 第一个参数:配置信息 [NSURLSessionConfiguration defaultSessionConfiguration] 第二个参数:代理 第三个参数:设置代理方法在哪个线程中调用 */ NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate :self delegateQueue:[NSOperationQueue mainQueue]]; //4.创建Task NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request]; //5.执行Task [dataTask resume]; //代理方法 ** * 1.接收到服务器的响应 它默认会取消该请求 * * @param session 会话对象 * @param dataTask 请求任务 * @param response 响应头信息 * @param completionHandler 回调 传给系统 */ -( void )URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:( void (^)(NSURLSessionResponseDisposition))completionHandler { 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.fileData appendData:data]; } /** * 请求结束或者是失败的时候调用 * * @param session 会话对象 * @param dataTask 请求任务 * @param error 错误信息 */ -( void )URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { NSLog( @"%s" ,__func__); //解析数据 NSLog( @"%@" ,[[NSString alloc]initWithData:self.fileData encoding:NSUTF8StringEncoding]); } |
三、大文件下载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | //1.url NSURL *url = [NSURL URLWithString: @"http://120.25.226.186:32812/resources/images/minion_03.png" ]; //2.创建请求对象 NSURLRequest *request = [NSURLRequest requestWithURL:url]; //3.创建session NSURLSession *session = [NSURLSession sharedSession]; //4.创建Task /* 第一个参数:请求对象 第二个参数:completionHandler 回调 location: response:响应头信息 error:错误信息 */ //该方法内部已经实现了边接受数据边写沙盒(tmp)的操作 NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) { //6.处理数据 NSLog( @"%@---%@" ,location,[NSThread currentThread]); //6.1 拼接文件全路径 NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename]; //6.2 剪切文件 [[NSFileManager defaultManager]moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil]; NSLog( @"%@" ,fullPath); }]; //7.执行Task [downloadTask resume]; } |
2.大文件下载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | /优点:不需要担心内存 //缺点:无法监听文件下载进度 -( void )download { //1.url NSURL *url = [NSURL URLWithString: @"http://120.25.226.186:32812/resources/images/minion_03.png" ]; //2.创建请求对象 NSURLRequest *request = [NSURLRequest requestWithURL:url]; //3.创建session NSURLSession *session = [NSURLSession sharedSession]; //4.创建Task /* 第一个参数:请求对象 第二个参数:completionHandler 回调 location: response:响应头信息 error:错误信息 */ //该方法内部已经实现了边接受数据边写沙盒(tmp)的操作 NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) { //6.处理数据 NSLog( @"%@---%@" ,location,[NSThread currentThread]); //6.1 拼接文件全路径 NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename]; //6.2 剪切文件 [[NSFileManager defaultManager]moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil]; NSLog( @"%@" ,fullPath); }]; //7.执行Task [downloadTask resume]; } -( void ) delegate { //1.url NSURL *url = [NSURL URLWithString: @"http://120.25.226.186:32812/resources/images/minion_03.png" ]; //2.创建请求对象 NSURLRequest *request = [NSURLRequest requestWithURL:url]; //3.创建session NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate :self delegateQueue:[NSOperationQueue mainQueue]]; //4.创建Task NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request]; //5.执行Task [downloadTask resume]; } #pragma mark ---------------------- #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 fileOffset 从什么地方下载 * @param expectedTotalBytes 文件的总大小 */ -( void )URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes { NSLog( @"%s" ,__func__); } /** * 当下载完成的时候调用 * * @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]; NSLog( @"%@" ,fullPath); } /** * 请求结束 */ -( void )URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { NSLog( @"didCompleteWithError" ); } |
3.下载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | @ interface ViewController ()<NSURLSessionDownloadDelegate> @property (nonatomic, strong) NSURLSessionDownloadTask *downloadTask; @property (nonatomic, strong) NSData *resumData; @property (nonatomic, strong) NSURLSession *session; @implementation ViewController - (IBAction)startBtnClick:(id)sender { //1.url NSURL *url = [NSURL URLWithString: @"http://120.25.226.186:32812/resources/videos/minion_01.mp4" ]; //2.创建请求对象 NSURLRequest *request = [NSURLRequest requestWithURL:url]; //3.创建session NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; self.session = [NSURLSession sessionWithConfiguration:config delegate :self delegateQueue:[NSOperationQueue mainQueue]]; //4.创建Task NSURLSessionDownloadTask *downloadTask = [self.session downloadTaskWithRequest:request]; //5.执行Task [downloadTask resume]; self.downloadTask = downloadTask; } //暂停是可以恢复 - (IBAction)suspendBtnClick:(id)sender { NSLog( @"+++++++++++++++++++暂停" ); [self.downloadTask suspend]; } //cancel:取消是不能恢复 //cancelByProducingResumeData:是可以恢复 - (IBAction)cancelBtnClick:(id)sender { NSLog( @"+++++++++++++++++++取消" ); //[self.downloadTask cancel]; //恢复下载的数据!=文件数据 [self.downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) { self.resumData = resumeData; }]; } - (IBAction)goOnBtnClick:(id)sender { NSLog( @"+++++++++++++++++++恢复下载" ); if (self.resumData) { self.downloadTask = [self.session downloadTaskWithResumeData:self.resumData]; } [self.downloadTask resume]; } //优点:不需要担心内存 //缺点:无法监听文件下载进度 -( void )download { //1.url NSURL *url = [NSURL URLWithString: @"http://120.25.226.186:32812/resources/images/minion_03.png" ]; //2.创建请求对象 NSURLRequest *request = [NSURLRequest requestWithURL:url]; //3.创建session NSURLSession *session = [NSURLSession sharedSession]; //4.创建Task /* 第一个参数:请求对象 第二个参数:completionHandler 回调 location: response:响应头信息 error:错误信息 */ //该方法内部已经实现了边接受数据边写沙盒(tmp)的操作 NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) { //5.处理数据 NSLog( @"%@---%@" ,location,[NSThread currentThread]); //5.1 拼接文件全路径 NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename]; //5.2剪切文件 [[NSFileManager defaultManager]moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil]; NSLog( @"%@" ,fullPath); }]; //6.执行Task [downloadTask resume]; } #pragma mark ---------------------- #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 fileOffset 从什么地方下载 * @param expectedTotalBytes 文件的总大小 */ -( void )URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes {NSLog( @"%s" ,__func__); } /** * 当下载完成的时候调用 * * @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]; NSLog( @"%@" ,fullPath); } /** * 请求结束 */ -( void )URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { NSLog( @"didCompleteWithError" ); } |
2.通过文件句柄下载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | <NSURLSessionDataDelegate> @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; - ( void )loadData{ //1.url NSURL *url = [NSURL URLWithString: @"http://120.25.226.186:32812/resources/videos/minion_02.mp4" ]; //2.创建请求对象 NSURLRequest *request = [NSURLRequest requestWithURL:url]; //3.创建会话对象,设置代理 /* 第一个参数:配置信息 [NSURLSessionConfiguration defaultSessionConfiguration] 第二个参数:代理 第三个参数:设置代理方法在哪个线程中调用 */ NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate :self delegateQueue:[NSOperationQueue mainQueue]]; //4.创建Task NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request]; //5.执行Task [dataTask resume]; } #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 { //获得文件的总大小 self.totalSize = response.expectedContentLength; //获得文件全路径 self.fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename]; //创建空的文件 [[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; } |
3.文件断点续传
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | @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; -(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]; } |
4、文件上传
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | #define Kboundary @"----WebKitFormBoundaryjv0UfA04ED44AhWx" #define KNewLine [@"\r\n" dataUsingEncoding:NSUTF8StringEncoding] @ interface ViewController ()<NSURLSessionDataDelegate> /** 注释 */ @property (nonatomic, strong) NSURLSession *session; -(NSURLSession *)session { if (_session == nil) { NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; //是否运行蜂窝访问 config.allowsCellularAccess = YES; config.timeoutIntervalForRequest = 15; _session = [NSURLSession sessionWithConfiguration:config delegate :self delegateQueue:[NSOperationQueue mainQueue]]; } return _session; } -( void )touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *) event { [self upload2]; } -( void )upload { //1.url NSURL *url = [NSURL URLWithString: @"http://120.25.226.186:32812/upload" ]; //2.创建请求对象 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; //2.1 设置请求方法 request.HTTPMethod = @"POST" ; //2.2 设请求头信息 [request setValue:[NSString stringWithFormat: @"multipart/form-data; boundary=%@" ,Kboundary] forHTTPHeaderField: @"Content-Type" ]; //3.创建会话对象 // NSURLSession *session = [NSURLSession sharedSession]; //4.创建上传TASK /* 第一个参数:请求对象 第二个参数:传递是要上传的数据(请求体) 第三个参数: */ NSURLSessionUploadTask *uploadTask = [self.session uploadTaskWithRequest:request fromData:[self getBodyData] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { //6.解析 NSLog( @"%@" ,[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]); }]; //5.执行Task [uploadTask resume]; } -( void )upload2 { //1.url NSURL *url = [NSURL URLWithString: @"http://120.25.226.186:32812/upload" ]; //2.创建请求对象 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; //2.1 设置请求方法 request.HTTPMethod = @"POST" ; //2.2 设请求头信息 [request setValue:[NSString stringWithFormat: @"multipart/form-data; boundary=%@" ,Kboundary] forHTTPHeaderField: @"Content-Type" ]; //3.创建会话对象 //4.创建上传TASK /* 第一个参数:请求对象 第二个参数:传递是要上传的数据(请求体) */ NSURLSessionUploadTask *uploadTask = [self.session uploadTaskWithRequest:request fromData:[self getBodyData] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { //6.解析 NSLog( @"%@" ,[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]); }]; //5.执行Task [uploadTask resume]; } -(NSData *)getBodyData { NSMutableData *fileData = [NSMutableData data]; //5.1 文件参数 /* --分隔符 Content-Disposition: form-data; name="file"; filename="Snip20160225_341.png" Content-Type: image/png(MIMEType:大类型/小类型) 空行 文件参数 */ [fileData appendData:[[NSString stringWithFormat: @"--%@" ,Kboundary] dataUsingEncoding:NSUTF8StringEncoding]]; [fileData appendData:KNewLine]; //name:file 服务器规定的参数 //filename:Snip20160225_341.png 文件保存到服务器上面的名称 //Content-Type:文件的类型 [fileData appendData:[ @"Content-Disposition: form-data; name=\" file\"; filename=\"Sss.png\"" dataUsingEncoding:NSUTF8StringEncoding]]; [fileData appendData:KNewLine]; [fileData appendData:[ @"Content-Type: image/png" dataUsingEncoding:NSUTF8StringEncoding]]; [fileData appendData:KNewLine]; [fileData appendData:KNewLine]; UIImage *image = [UIImage imageNamed: @"Snip20160226_90" ]; //UIImage --->NSData NSData *imageData = UIImagePNGRepresentation(image); [fileData appendData:imageData]; [fileData appendData:KNewLine]; //5.2 非文件参数 /* --分隔符 Content-Disposition: form-data; name="username" 空行 123456 */ [fileData appendData:[[NSString stringWithFormat: @"--%@" ,Kboundary] dataUsingEncoding:NSUTF8StringEncoding]]; [fileData appendData:KNewLine]; [fileData appendData:[ @"Content-Disposition: form-data; name=\" username\"" dataUsingEncoding:NSUTF8StringEncoding]]; [fileData appendData:KNewLine]; [fileData appendData:KNewLine]; [fileData appendData:[ @"123456" dataUsingEncoding:NSUTF8StringEncoding]]; [fileData appendData:KNewLine]; //5.3 结尾标识 /* --分隔符-- */ [fileData appendData:[[NSString stringWithFormat: @"--%@--" ,Kboundary] dataUsingEncoding:NSUTF8StringEncoding]]; return fileData; } #pragma mark NSURLSessionDataDelegate /* * @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); } |
将来的自己,会感谢现在不放弃的自己!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现