iOS 中如何实现断点续传的功能
思路:
001 该类继承NSURLSessionDataDelegate代理
002 每次请求的时候都到本地缓存获取对应的数据流大小 然后更新self.currentSize
003 对NSMutableURLRequest 的forHTTPHeaderField:进行处理
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//设置请求头
NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentSize];
[request setValue:range forHTTPHeaderField:@"Range"];
004 将下载数据存到本地缓存
在收到服务器响应的代理方法中 获取总容量,将输出流对应到本地缓存目录下
打开接收流 允许请求执行
在收到下载数据的代理方法中 将下载得到数据流写入到本地缓存的目录下
同时更新当前进度数据
代码如下:
//
// ViewController.m
// LearnDownloader
//
// Created by maochengfang on 2020/10/21.
//
#import "ViewController.h"
#define kFileName @"124.mp4"
@interface ViewController ()
@property (nonatomic, strong) NSOutputStream *stream;
@property (nonatomic, assign) NSInteger totalSize;
@property (nonatomic, assign) NSInteger currentSize;
@property (nonatomic, strong) NSURLSessionDataTask *downloadTask;
@property (nonatomic, strong) NSURLSession *session;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self startDownLoad];
}
- (NSURLSession *)session{
if(!_session){
_session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
}
return _session;
}
- (NSURLSessionDataTask *)downloadTask{
if(!_downloadTask){
self.currentSize = [self getCurrentSize];
NSURL *url = [NSURL URLWithString:@"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603304688338&di=54159a129fde063b53e4b8e13d90c4e8&imgtype=0&src=http%3A%2F%2Ft9.baidu.com%2Fit%2Fu%3D1307125826%2C3433407105%26fm%3D79%26app%3D86%26f%3DJPEG%3Fw%3D5760%26h%3D3240"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//设置请求头
NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentSize];
[request setValue:range forHTTPHeaderField:@"Range"];
_downloadTask = [self.session dataTaskWithRequest:request];
}
return _downloadTask;
}
- (void)startDownLoad{
[self.downloadTask resume];
}
- (void)pauseDownLoad{
[self.downloadTask suspend];
}
- (NSInteger)getCurrentSize{
NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:kFileName];
NSDictionary *fileDic = [[NSFileManager defaultManager] attributesOfItemAtPath:fullPath error:nil];
return [fileDic[@"NSFileSize"] integerValue];
}
//------------------------------
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(nonnull NSURLResponse *)response completionHandler:(nonnull void (^)(NSURLSessionResponseDisposition))completionHandler{
self.totalSize = response.expectedContentLength + self.currentSize;
NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:kFileName];
self.stream = [[NSOutputStream alloc] initToFileAtPath:fullPath append:YES];
[self.stream open];
completionHandler(NSURLSessionResponseAllow);
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{
[self.stream write:data.bytes maxLength:data.length];
self.currentSize += data.length;
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
[self.stream close];
self.stream = nil;
}
- (void)dealloc{
[self.session invalidateAndCancel];
}
@end