iOS网络学习之“远离NSURLConnection 走进NSURLSession”
目前,在iOS的开发中,NURLConnection已经成为了过去式,现在的NSURLConnection已经deprected(iOS7之后),取而代之的是NSURLSession。而且AFNetworking 也已经换成了NSURLSession。既然是大势所趋,现总结NSURLSession用法如下:
首先,是根据简单地按钮实现对应的网络操作:
1.NSURLSessiion 的GET网络请求:
要实现网络请求,首先,要准备好URLl 和 必要的参数,而GET最大的特点就是参数是直接的拼接在URL的后面,(路径?参数名=参数值)。然后,就可以通过NSURLSession和NSURLSessionTask愉快的进行GET网络请求了。注意,task要手动开启[task resume];。
具体使用代码如下:
- (IBAction)oneAction:(UIButton *)sender { /** * get请求 * */ NSString * name=@"jredu"; NSString * psw=@"123"; NSURL * url=[NSURLURLWithString:[NSStringstringWithFormat:@"http://localhost/logo.php?userName=%@&pwd=%@",name,psw]]; //>初始化session NSURLSession * session=[NSURLSessionsharedSession]; NSURLSessionTask * task=[session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { //将返回的二进制数据转为字符串 NSString * str=[[NSStringalloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"%@",str); }]; //开始任务 [task resume]; }
2.使用NSURLSession进行POST网络请求:
通过POST方式请求网络,同样是准备好URL,而与GET方式的不同之处:POST时,所需的参数并不是拼接在URL上的,POST的参数通过NSURLRequest传递(NSData);
准备好参数和URL之后任然是通过NSURLSession和NSURLSessionTask进行网络请求。同样注意:手动开启任务[task resume];
具体的使用代码如下:
#pragma mark - post请求 - (IBAction)twoAction:(UIButton *)sender { NSString *name=@"codeJerenal"; NSString *psw=@"123"; NSURL * url =[NSURLURLWithString:@"http://localhost/login_post.php"]; NSString * dataStr=[NSStringstringWithFormat:@"userName=%@&psw=%@",name,psw]; /** 字符串转data */ NSData * data=[dataStr dataUsingEncoding:NSUTF8StringEncoding]; /** 初始化可变的请求--设置数据 */ NSMutableURLRequest * request=[NSMutableURLRequestrequestWithURL:url]; [request setHTTPMethod:@"POST"]; [request setHTTPBody:data]; /** 初始化session */ NSURLSession * session=[NSURLSessionsharedSession]; NSURLSessionTask * task=[session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { /** data转字符串调用类方法 */ NSString *retutnStr=[[NSStringalloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"%@",retutnStr); }]; //>开始任务 [task resume]; }
3,使用NSURLSession下载:
要下载数据,首先,要给出要下载的资源的网络路径URL;
NSURLSession 可以通过NSURLRequest初始化NSURLSession下载,也可以直接使用URL;
下载成功之后的文件、数据会放在沙盒中的tmp文件中,作为一个临时的文件(返回的location就是其本地的URL),所以在下载成功之后的块中,要及时的将所下载的内容转移到Document中存放(通过NSFileManager)。在移动文件的过程中要注意location是本地的URL 所以,目的地路劲也是URL 应该使用[NSURL fileURLWithString:string];
在下载完成之后,还会返回一个,NSURLResponse * response,可以通过其中的属性response.suggestedFileame作为文件在本地的命名;
具体的使用如下所示:
#pragma mark - 下载数据 - (IBAction)sessionDownLoadAction:(UIButton *)sender { //>URL路径 NSURL * url=[NSURLURLWithString:@"http://localhost/test.zip"]; //>初始化session NSURLSession * session=[NSURLSessionsharedSession]; //>定义request NSURLRequest * request=[NSURLRequestrequestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicytimeoutInterval:20]; //>定义任务 NSURLSessionDownloadTask * downLoadTask=[session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) { //本地沙盒路径 NSString * path=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; //文件下载后的存放路径-(转为本地URL使用)(字符串拼接方式,构造本地路径) // NSString * fPath=[path stringByAppendingPathComponent:response.suggestedFilename]; /** 转换 */ // NSURL * desUrl=[NSURL fileURLWithPath:fPath]; /** 为本地路径准备path (格式化方式,构造本地路径)*/ NSString * filePath=[NSStringstringWithFormat:@"file://%@/%@",path,response.suggestedFilename]; /** 转为本地的URL */ NSURL * destinationUrl=[NSURLURLWithString:filePath]; //移动 NSFileManager * manager =[NSFileManagerdefaultManager]; NSError * error2; BOOL isSuccess = [manager moveItemAtURL:location toURL:destinationUrl error:&error2]; if (isSuccess) { NSLog(@"成功"); }else{ NSLog(@"失败"); NSLog(@"%@",error2); } }]; [task resume]; }
4,NSURLSession实现下载的暂停和继续;
①:过程中要用到代理方法,而NSURLSession是在初始化的同时设置代理的,并且同时进行下载的设置
NSURLSessionConfiguration
参数一 session配置
参数二设置代理
参数三设置代理队列
NSURLSession * session = [NSURLSessionsessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:selfdelegateQueue:[NSOperationQueuemainQueue]];
②:通过按钮(或其他的方式)控制下载的暂停继续:
核心:取消下载任务并保存已经下载的数据
[self.downTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
self.resumeData=resumeData;
}];
核心: 通过之前保存的已经下载的数据,继续下载
self.downTask =[self.session downloadTaskWithResumeData:self.resumeData];
[self.downTask resume];
#pragma mark - 控制起停按钮,点击事件 - (void) clickAction:(UIButton *)button{ button.selected=!button.selected; if (button.selected) { [self.downTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) { /** 全局,用作断点下载存放已经下载的数据*/ self.resumeData=resumeData; }]; }else{ self.downTask =[self.session downloadTaskWithResumeData:self.resumeData]; /** 重新启动任务 */ [self.downTask resume]; } }
③:下载过程中的主要代理方法
#pragma mark - 下载数据的代理方法 /** * 代理方法:每次数据下载成功调用方法 * * @param session 代理的session * @param downloadTask 代理的task * @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{ NSLog(@"%lld===%lld=====%lld",bytesWritten,totalBytesWritten,totalBytesExpectedToWrite); /** 主线程显示下载进度 */ dispatch_async(dispatch_get_main_queue(), ^{ if (totalBytesWritten==totalBytesExpectedToWrite) { _curProgress.frame=CGRectMake(20, 500, 320, 30); }else{ _curProgress.frame=CGRectMake(20, 500, totalBytesWritten*(1.0)/totalBytesExpectedToWrite*(1.0)*320, 30); /** 随机背景色 */ _curProgress.backgroundColor=[UIColorcolorWithRed:arc4random_uniform(255)/255.0green:arc4random_uniform(255)/255.0blue:arc4random_uniform(255)/255.0alpha:1]; } }); }
/** * 代理方法:下载完成时调用--已经下载的文件从临时存放处移动到document中 * * @param session 代理的session * @param downloadTask 代理的task * @param location 下载文件的临时存放路径 */ - (void) URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{ NSString * documentPath=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; NSString * filePath =[documentPath stringByAppendingPathComponent:downloadTask.response.suggestedFilename]; NSURL * loaclUrl =[NSURLfileURLWithPath:filePath]; NSLog(@"%@",loaclUrl); //移动 NSError * err; BOOL isSuccess=[[NSFileManagerdefaultManager] moveItemAtURL:location toURL:loaclUrl error:&err]; if (isSuccess) { NSLog(@"下载成功"); }else{ NSLog(@"失败"); NSLog(@"%@",err); } }
#pragma mark *** 下载结束 - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{ /** 如果是其他的原因导致下载失败,程序会走本方法,可以通过 self.resumeData = error[NSURLSessionDownloadTaskResumeData]; 找到已经下载的数据,解决失败原因之后,可以继续下载 */ if (error) {
NSLog(@"%@",error);
}else { NSLog(@"成功"); } }