首先明白什么是真正的断点下载:
1. 就是在程序退出后台后当下次进入仍可以继续下载
2. 思路:结合NSFileHandle来获取已经下载的部分,在在其后下载来自网络的其他部分。
3. 网络部分:给请求添加请求头关键字:‘bytes’
话不多说直接上代码:
*
import “ViewController.h”
@interface ViewController ()
pragma mark - UIResponder
- (void)touchesBegan:(NSSet
pragma mark - custom methods
- (NSString *)filePath
{
NSString *docPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
return [docPath stringByAppendingPathComponent:@”1.mov”];
}
pragma mark - NSURLSessionDelegate
// 接收到响应 4、响应会根据block调用所传的值来判断是否继续响应数据
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{
NSLog(@”%d____%s”, [NSThread isMainThread], FUNCTION);
NSHTTPURLResponse httpResponse = (NSHTTPURLResponse )response;
NSDictionary *responseHeaders = httpResponse.allHeaderFields;
_expectedTotalLength = _recievedLength + [responseHeaders[@”Content-Length”] longLongValue];
// 判断block是否存在
if (completionHandler) {
NSLog(@"%@", [self filePath]);
// 如果不存在文件 创建一个
if (![[NSFileManager defaultManager] fileExistsAtPath:[self filePath]])
{
[[NSFileManager defaultManager] createFileAtPath:[self filePath] contents:nil attributes:nil];
}
// 根据路径创建fileHandle 如果路径不存在 则返回nil
self.fileHandle = [NSFileHandle fileHandleForWritingAtPath:[self filePath]];
// 设置允许继续加载
completionHandler(NSURLSessionResponseAllow);
}
}
// 此方法表示已经接收到数据 如果数据量有点大,数据会分段返回,此方法会执行多次
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data
{
// 接收一点数据 就像磁盘写入
// 切换至文件末尾
[self.fileHandle seekToEndOfFile];
[self.fileHandle writeData:data];
_recievedLength += data.length;
NSLog(@"%lld_____%lld", _recievedLength, _expectedTotalLength);
NSLog(@"%d____%s", [NSThread isMainThread], __FUNCTION__);
}
// 任务完成 1.遇到错误 2.成功
- (void)URLSession:(NSURLSession )session task:(NSURLSessionTask )task
didCompleteWithError:(nullable NSError *)error
{
NSLog(@”%d____%s”, [NSThread isMainThread], FUNCTION);
if(!error)
{
// 成功
}
else
{
NSLog(@"error:%@", error);
}
}
pragma mark - override setter getter
(NSURLSessionDataTask *)dataTask
{
if (!_dataTask) {
NSString *path = @”http://localhost:8080/UploadFileServer/19 上传大文件.mov”;
// 路径中有中文 编码
NSString *encodePath = [path stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
NSURL *url = [NSURL URLWithString:encodePath];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];NSFileManager *fileManger = [NSFileManager defaultManager]; if ([fileManger fileExistsAtPath:[self filePath]]) { // 获取文件的属性 NSDictionary *fileInfo = [fileManger attributesOfItemAtPath:[self filePath] error:nil]; NSNumber *fileSizeNumber = fileInfo[NSFileSize]; NSString *rangeStr = [NSString stringWithFormat:@"bytes=%@-", [fileSizeNumber stringValue]]; // 添加请求头 [request setValue:rangeStr forHTTPHeaderField:@"Range"]; _recievedLength = [fileSizeNumber longLongValue]; } // session创建任务 _dataTask = [self.session dataTaskWithRequest:request];
}
return _dataTask;
}(NSURLSession *)session
{
if (!_session) {
// 创建会话配置
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
// 设置超时时间
config.timeoutIntervalForRequest = 30.f;
/*
*创建session
1.会话配置
2.代理 如果不设置 跟configBlock中创建session的方式差不多
3.指定代理回调所执行的队列
*/
_session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
}
return _session;
}
*