-
使用步骤
- 使用NSURLSession对象创建Task,然后执行Task
Task的类型
获得获得NSURLSession
- 获得共享的Session
+ (NSURLSession *)sharedSession;
- 自定义Session
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(id )delegate delegateQueue:(NSOperationQueue *)queue;
NSURLSessionTask
- 常见方法
- (void)suspend; // 暂停
- (void)resume; // 恢复
- (void)cancel; // 取消
@property (readonly, copy) NSError *error; // 错误
@property (readonly, copy) NSURLResponse *response; // 响应
NSURLSessionDownloadTask
- 常见方法
- (void)cancelByProducingResumeData:(void (^)(NSData *resumeData))completionHandler; // 取消任务
1. NSURLSessionDownloadTask大文件下载(block)
#define SCREENWIDTH [UIScreen mainScreen].bounds.size.width
#define SCREENHEIGHT [UIScreen mainScreen].bounds.size.height
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic,strong) UIButton * btn;
@end
@implementation ViewController
-(UIButton *)btn
{
if (!_btn) {
_btn = [UIButton buttonWithType:UIButtonTypeCustom];
_btn.frame = CGRectMake(SCREENWIDTH / 2 - 75, SCREENHEIGHT / 2 - 15, 150, 30);
[_btn setTitle:@"点击" forState:UIControlStateNormal];
[_btn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[_btn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];
}
return _btn;
}
-(void)clickBtn:(UIButton *)btn
{
[self download];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.btn];
}
// 优点: 不需要担心内存问题
// 缺点: 无法监听文件下载进度
-(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];
// 拼接文件名
fullPath = [fullPath stringByAppendingPathComponent:response.suggestedFilename];
NSLog(@"开始前:%@",fullPath);
// 6.2 剪切文件
/*
第一参数: 需要剪切的文件在哪里
第二参数: 该文件要剪切到什么地方去
第三参数: 错误信息
*/
[[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil];
NSLog(@"%@",fullPath);
}];
// 5. 执行Task
[downloadTask resume];
}
@end
2. NSURLSessionDownloadTask大文件下载(delegate)
#define SCREENWIDTH [UIScreen mainScreen].bounds.size.width
#define SCREENHEIGHT [UIScreen mainScreen].bounds.size.height
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic,strong) UIButton * btn;
@end
@implementation ViewController
-(UIButton *)btn
{
if (!_btn) {
_btn = [UIButton buttonWithType:UIButtonTypeCustom];
_btn.frame = CGRectMake(SCREENWIDTH / 2 - 75, SCREENHEIGHT / 2 - 15, 150, 30);
[_btn setTitle:@"点击" forState:UIControlStateNormal];
[_btn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[_btn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];
}
return _btn;
}
-(void)clickBtn:(UIButton *)btn
{
[self delegate];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.btn];
}
-(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 - 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(@"%s",__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];
// 2.拼接文件
fullPath = [fullPath stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
// 3. 剪切文件
[[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil];
NSLog(@"保存缓存:%@",fullPath);
}
/**
* 当请求结束的时候调用该方法
*
* @param session 会话对象
* @param task 下载任务
* @param error 错误信息
*/
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
NSLog(@"%s",__func__);
}
@end
3. NSURLSessionDownloadTask大文件下载(断点下载)
#define SCREENWIDTH [UIScreen mainScreen].bounds.size.width
#define SCREENHEIGHT [UIScreen mainScreen].bounds.size.height
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic,strong) UIButton * startBtn;
@property (nonatomic,strong) UIButton * pauseBtn;
@property (nonatomic,strong) UIButton * cancelBtn;
@property (nonatomic,strong) UIButton * continueBtn;
// session
@property (nonatomic,strong) NSURLSession * session;
// Task
@property (nonatomic,strong) NSURLSessionDownloadTask * downloadTask;
@property (nonatomic,strong) NSData * newrResumeData;
@end
@implementation ViewController
-(UIButton *)startBtn
{
if (!_startBtn) {
_startBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_startBtn.frame = CGRectMake(SCREENWIDTH / 2 - 75, 80, 150, 30);
[_startBtn setTitle:@"开始下载" forState:UIControlStateNormal];
[_startBtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[_startBtn setTitleColor:[UIColor blueColor] forState:UIControlStateSelected];
[_startBtn addTarget:self action:@selector(clickStartBtn:) forControlEvents:UIControlEventTouchUpInside];
}
return _startBtn;
}
-(UIButton *)pauseBtn
{
if (!_pauseBtn) {
_pauseBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_pauseBtn.frame = CGRectMake(SCREENWIDTH / 2 - 75, 130, 150, 30);
[_pauseBtn setTitle:@"暂停下载" forState:UIControlStateNormal];
[_pauseBtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[_pauseBtn addTarget:self action:@selector(clickPauseBtn:) forControlEvents:UIControlEventTouchUpInside];
}
return _pauseBtn;
}
-(UIButton *)cancelBtn
{
if (!_cancelBtn) {
_cancelBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_cancelBtn.frame = CGRectMake(SCREENWIDTH / 2 - 75, 190, 150, 30);
[_cancelBtn setTitle:@"取消下载" forState:UIControlStateNormal];
[_cancelBtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[_cancelBtn addTarget:self action:@selector(clickCancelBtn:) forControlEvents:UIControlEventTouchUpInside];
}
return _cancelBtn;
}
-(UIButton *)continueBtn
{
if (!_continueBtn) {
_continueBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_continueBtn.frame = CGRectMake(SCREENWIDTH / 2 - 75, 250, 150, 30);
[_continueBtn setTitle:@"继续下载" forState:UIControlStateNormal];
[_continueBtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[_continueBtn addTarget:self action:@selector(clickContinueBtn:) forControlEvents:UIControlEventTouchUpInside];
}
return _continueBtn;
}
-(void)clickStartBtn:(UIButton *)btn
{
// [self download];
[self delegate];
}
// 暂停,可以恢复
-(void)clickPauseBtn:(UIButton *)btn
{
NSLog(@"------暂停------");
[self.downloadTask suspend];
}
// cancel : 取消,不能恢复
// cancelByProducingResumeData: 是可以恢复的
-(void)clickCancelBtn:(UIButton *)btn
{
NSLog(@"------取消------");
// [self.downloadTask cancel];
// 恢复下载的数据 !=(不等于) 文件数据
[self.downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
self.newrResumeData = resumeData;
}];
}
-(void)clickContinueBtn:(UIButton *)btn
{
NSLog(@"------继续------");
if (self.newrResumeData != nil) {
self.downloadTask = [self.session downloadTaskWithResumeData:self.newrResumeData];
}
[self.downloadTask resume];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.startBtn];
[self.view addSubview:self.pauseBtn];
[self.view addSubview:self.cancelBtn];
[self.view addSubview:self.continueBtn];
}
// 优点: 不需要担心内存问题
// 缺点: 无法监听文件下载进度
-(void)download
{
// 1. 确定URL
NSURL * url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_03.mp4"];
// 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];
// 拼接文件名
fullPath = [fullPath stringByAppendingPathComponent:response.suggestedFilename];
NSLog(@"开始前:%@",fullPath);
// 6.2 剪切文件
/*
第一参数: 需要剪切的文件在哪里
第二参数: 该文件要剪切到什么地方去
第三参数: 错误信息
*/
[[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil];
NSLog(@"%@",fullPath);
}];
// 5. 执行Task
[downloadTask resume];
}
-(void)delegate
{
// 1. 确定URL
NSURL * url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_03.mp4"];
// 2. 创建请求对象
NSURLRequest * request = [NSURLRequest requestWithURL:url];
// 3. 创建session
self.session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
// 4. 创建Task
NSURLSessionDownloadTask * downloadTask = [self.session downloadTaskWithRequest:request];
// 5. 执行Task
[downloadTask resume];
self.downloadTask = downloadTask;
}
#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(@"%s",__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];
// 2.拼接文件
fullPath = [fullPath stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
// 3. 剪切文件
[[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil];
NSLog(@"保存缓存:%@",fullPath);
}
/**
* 当请求结束的时候调用该方法
*
* @param session 会话对象
* @param task 下载任务
* @param error 错误信息
*/
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
NSLog(@"%s",__func__);
}
@end
4. NSURLSessionDataTask实现大文件下载
#define SCREENWIDTH [UIScreen mainScreen].bounds.size.width
#define SCREENHEIGHT [UIScreen mainScreen].bounds.size.height
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic,strong) UIButton * btn;
/** 下载进度条 */
@property (nonatomic,strong) UIProgressView * progressView;
/** 文件句柄 */
@property (nonatomic,strong) NSFileHandle * handle;
/** 下载总大小 */
@property (nonatomic,assign) NSInteger totalSize;
/** 当前下载大小 */
@property (nonatomic,assign) NSInteger currentSize;
/** 文件的全路径 */
@property (nonatomic,strong) NSString * fullPath;
@end
@implementation ViewController
-(UIButton *)btn
{
if (!_btn) {
_btn = [UIButton buttonWithType:UIButtonTypeCustom];
_btn.frame = CGRectMake(SCREENWIDTH / 2 -75 , SCREENHEIGHT / 2 -15, 150, 30);
[_btn setTitle:@"点击" forState:UIControlStateNormal];
[_btn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[_btn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];
}
return _btn;
}
- (UIProgressView *)progressView
{
if (!_progressView) {
_progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(SCREENWIDTH / 2 - 100, 80, 200, 30)];
_progressView.progress = 0;
}
return _progressView;
}
-(void)clickBtn:(UIButton *)btn
{
// 1. 确定URL
NSURL * url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_03.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];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.btn];
[self.view addSubview:self.progressView];
}
#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];
// 拼接文件名称
self.fullPath = [self.fullPath 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;
CGFloat progressF = 1.0 * self.currentSize / self.totalSize;
// 进度条显示进度状态
self.progressView.progress = progressF;
// 计算文件的下载进度
NSLog(@"%f",1.0 * self.currentSize / self.totalSize);
}
/**
* 请求结束或者是失败的时候调用
*
* @param session 会话对象
* @param task 请求任务
* @param error 错误信息
*/
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
NSLog(@"下载好后的文件:%@",self.fullPath);
// 关闭文件句柄
[self.handle closeFile];
self.handle = nil;
}
@end
5. NSURLSessionDataTask离线断点下载(断点续传)
#define SCREENWIDTH [UIScreen mainScreen].bounds.size.width
#define SCREENHEIGHT [UIScreen mainScreen].bounds.size.height
#define FileName @"03.mp4"
#define TOTASLSIZE @"totalSize"
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic,strong) UIButton * startBtn;
@property (nonatomic,strong) UIButton * pauseBtn;
@property (nonatomic,strong) UIButton * cancelBtn;
@property (nonatomic,strong) UIButton * continueBtn;
// session
@property (nonatomic,strong) NSURLSession * session;
// Task
@property (nonatomic,strong) NSURLSessionDataTask * dataTask;
/** 下载进度条 */
@property (nonatomic,strong) UIProgressView * progressView;
/** 文件句柄 */
@property (nonatomic,strong) NSFileHandle * handle;
/** 下载总大小 */
@property (nonatomic,assign) NSInteger totalSize;
/** 当前下载大小 */
@property (nonatomic,assign) NSInteger currentSize;
/** 文件的全路径 */
@property (nonatomic,strong) NSString * fullPath;
@end
@implementation ViewController
-(UIButton *)startBtn
{
if (!_startBtn) {
_startBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_startBtn.frame = CGRectMake(SCREENWIDTH / 2 - 75, 80, 150, 30);
[_startBtn setTitle:@"开始下载" forState:UIControlStateNormal];
[_startBtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[_startBtn setTitleColor:[UIColor blueColor] forState:UIControlStateSelected];
[_startBtn addTarget:self action:@selector(clickStartBtn:) forControlEvents:UIControlEventTouchUpInside];
}
return _startBtn;
}
-(UIButton *)pauseBtn
{
if (!_pauseBtn) {
_pauseBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_pauseBtn.frame = CGRectMake(SCREENWIDTH / 2 - 75, 130, 150, 30);
[_pauseBtn setTitle:@"暂停下载" forState:UIControlStateNormal];
[_pauseBtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[_pauseBtn addTarget:self action:@selector(clickPauseBtn:) forControlEvents:UIControlEventTouchUpInside];
}
return _pauseBtn;
}
-(UIButton *)cancelBtn
{
if (!_cancelBtn) {
_cancelBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_cancelBtn.frame = CGRectMake(SCREENWIDTH / 2 - 75, 190, 150, 30);
[_cancelBtn setTitle:@"取消下载" forState:UIControlStateNormal];
[_cancelBtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[_cancelBtn addTarget:self action:@selector(clickCancelBtn:) forControlEvents:UIControlEventTouchUpInside];
}
return _cancelBtn;
}
-(UIButton *)continueBtn
{
if (!_continueBtn) {
_continueBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_continueBtn.frame = CGRectMake(SCREENWIDTH / 2 - 75, 250, 150, 30);
[_continueBtn setTitle:@"继续下载" forState:UIControlStateNormal];
[_continueBtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[_continueBtn addTarget:self action:@selector(clickContinueBtn:) forControlEvents:UIControlEventTouchUpInside];
}
return _continueBtn;
}
-(NSString *)fullPath
{
if (!_fullPath) {
// 获得文件全路径
_fullPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
// 拼接文件名称
_fullPath = [self.fullPath stringByAppendingPathComponent:FileName];
}
return _fullPath;
}
-(NSURLSession *)session
{
if (!_session) {
// 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_03.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"];
// NSLog(@"请求体信息: %@",range);
// 4. 创建Task
_dataTask = [self.session dataTaskWithRequest:request];
}
return _dataTask;
}
#pragma mark - 获得指定文件路径对应文件的数据大小
-(NSInteger)getFileSize
{
// 获得指定文件路径对应文件的数据大小
NSDictionary * fileInfoDict = [[NSFileManager defaultManager] attributesOfItemAtPath:self.fullPath error:nil];
NSLog(@"%@",fileInfoDict);
NSInteger currentSize = [fileInfoDict[@"NSFileSize"] integerValue];
return currentSize;
}
-(void)clickStartBtn:(UIButton *)btn
{
[self download];
}
// 暂停,可以恢复
-(void)clickPauseBtn:(UIButton *)btn
{
NSLog(@"------暂停------");
[self.dataTask suspend];
}
// 该取消是不能恢复的
-(void)clickCancelBtn:(UIButton *)btn
{
NSLog(@"------取消------");
[self.dataTask cancel];
self.dataTask = nil;
}
-(void)clickContinueBtn:(UIButton *)btn
{
NSLog(@"------继续------");
[self.dataTask resume];
}
- (UIProgressView *)progressView
{
if (!_progressView) {
_progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(SCREENWIDTH / 2 - 100, 50, 200, 30)];
_progressView.progress = 0;
}
return _progressView;
}
-(void)download
{
// // 1. 确定URL
// NSURL * url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_03.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
[self.dataTask resume];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.startBtn];
[self.view addSubview:self.pauseBtn];
[self.view addSubview:self.cancelBtn];
[self.view addSubview:self.continueBtn];
[self.view addSubview:self.progressView];
// 1. 读取保存的文件总数据大小,0
NSInteger totalSize = [self getTotalSize];
if (totalSize == 0) {
self.progressView.progress = 0;
}else{
// 2. 获取当前已经下载的数据大小
// 3. 计算的到进度信息
self.progressView.progress = 1.0 * self.currentSize / totalSize;
}
NSLog(@"总大小为:%zd",totalSize);
}
#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;
// 把数据总大小用NSUserDefaults纪录保存
[self saveTotalSize:self.totalSize];
// // 获得文件全路径
// self.fullPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
// // 拼接文件名称
// self.fullPath = [self.fullPath stringByAppendingPathComponent:response.suggestedFilename];
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;
CGFloat progressF = 1.0 * self.currentSize / self.totalSize;
// 进度条显示进度状态
self.progressView.progress = progressF;
// 计算文件的下载进度
NSLog(@"%f",1.0 * self.currentSize / self.totalSize);
}
/**
* 请求结束或者是失败的时候调用
*
* @param session 会话对象
* @param task 请求任务
* @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];
}
#pragma mark - 把数据总大小用NSUserDefaults纪录保存
-(void)saveTotalSize:(NSInteger)size
{
NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
[defaults setInteger:size forKey:TOTASLSIZE];
[defaults synchronize];
}
#pragma mark - 获取下载数据总大小
-(NSInteger)getTotalSize
{
NSInteger size = [[[NSUserDefaults standardUserDefaults] objectForKey:TOTASLSIZE] integerValue];
return size;
}
@end
6. 掌握NSURLSession实现文件上传
#define SCREENWIDTH [UIScreen mainScreen].bounds.size.width
#define SCREENHEIGHT [UIScreen mainScreen].bounds.size.height
// 设置boundary的宏
#define Kboundary @"----WebKitFormBoundaryaItGoVAfuLHDoRD4"
#define KNewLine [@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic,strong) UIButton * btn;
/** 进度条控件 */
@property (nonatomic,strong) UIProgressView * progressView;
@property (nonatomic,strong) NSURLSession * session;
@end
@implementation ViewController
-(UIButton *)btn
{
if (!_btn) {
_btn = [UIButton buttonWithType:UIButtonTypeCustom];
_btn.frame = CGRectMake(SCREENWIDTH / 2 - 75, SCREENHEIGHT / 2 - 15, 150, 30);
[_btn setTitle:@"上传" forState:UIControlStateNormal];
[_btn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[_btn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];
}
return _btn;
}
-(UIProgressView *)progressView
{
if (_progressView == nil) {
_progressView = [[UIProgressView alloc] init];
_progressView.frame = CGRectMake(SCREENWIDTH / 2 - 100, 80, 200, 30);
// 设置进度条进度
_progressView.progress = 0;
}
return _progressView;
}
-(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)clickBtn:(UIButton *)btn
{
[self upload];
// [self upload2];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.btn];
[self.view addSubview:self.progressView];
}
-(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"];
// NSData * bodyData = [self getBodyData];
//
// // 2.3 设置请求体信息
// request.HTTPBody = bodyData;
// 3. 创建会话对象
// NSURLSession * session = [NSURLSession sharedSession];
// 4. 创建上传Task
/*
第一参数: 请求对象
第二参数: 二进制数据,传递要上传的数据(请求体)
第三参数: completionHandler 回调
data: 响应体信息
response: 响应头信息
error: 错误信息
*/
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"];
// NSData * bodyData = [self getBodyData];
//
// // 2.3 设置请求体信息
// request.HTTPBody = bodyData;
// 3. 创建会话对象
// NSURLSession * session = [NSURLSession sharedSession];
// NSURLSession * session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
// 4. 创建上传Task
/*
第一参数: 请求对象
第二参数: 二进制数据,传递要上传的数据(请求体)
第三参数: completionHandler 回调
data: 响应体信息
response: 响应头信息
error: 错误信息
*/
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="静态05.jpg"
Content-Type: image/jpeg(MIMEType:大类型/小类型)
空行
文件参数
*/
NSData * oneData = [[NSString stringWithFormat:@"--%@",Kboundary] dataUsingEncoding:NSUTF8StringEncoding];
[fileData appendData:oneData];
// 把换行添加进请求体数据中
[fileData appendData:KNewLine];
// name:file 服务器规定的参数
// filename: 静态05.jpg 文件保存到服务器上面的名称
// Content-Type: 文件的类型
NSData * twoData = [@"Content-Disposition: form-data; name=\"file\"; filename=\"静态05.jpg\"" dataUsingEncoding:NSUTF8StringEncoding];
[fileData appendData:twoData];
[fileData appendData:KNewLine];
NSData * thirdlyData = [@"Content-Type: image/jpeg" dataUsingEncoding:NSUTF8StringEncoding];
[fileData appendData:thirdlyData];
[fileData appendData:KNewLine];
[fileData appendData:KNewLine];
UIImage * image = [UIImage imageNamed:@"静态05"];
// UIImage --> NSData
NSData * imageData = UIImageJPEGRepresentation(image, 0.5);
[fileData appendData:imageData];
[fileData appendData:KNewLine];
// 5.2 非文件参数
/*
--分隔符
Content-Disposition: form-data; name="username"
空行
456123
*/
NSData * sixthData = [[NSString stringWithFormat:@"--%@",Kboundary] dataUsingEncoding:NSUTF8StringEncoding];
[fileData appendData:sixthData];
[fileData appendData:KNewLine];
NSData * seventhData = [@"Content-Disposition: form-data; name=\"username\"" dataUsingEncoding:NSUTF8StringEncoding];
[fileData appendData:seventhData];
[fileData appendData:KNewLine];
[fileData appendData:KNewLine];
NSData * ninthData = [@"456123" dataUsingEncoding:NSUTF8StringEncoding];
[fileData appendData:ninthData];
[fileData appendData:KNewLine];
// 5.3 结尾标识
NSData * tenthData = [[NSString stringWithFormat:@"--%@--",Kboundary] dataUsingEncoding:NSUTF8StringEncoding];
[fileData appendData:tenthData];
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);
self.progressView.progress = 1.0 * totalBytesSent / totalBytesExpectedToSend;
}
@end