okay,NSURLConnection在iOS9.0之后已经被废弃掉了,当然我们在开发中不免会遇到一些NSURLConnection的代码,到时候知道如何处理就Ok了,我们的重点是要好好聊心啊NSURLSession
NSURLSession
- 使用步骤:
- 使用NSURLSession对象创建Task,然后执行Task
-
Task的类型
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);
}