关于NSURLSession的断点续传的特点:
在运行的时候,能够暂停和继续,但是一旦退出,就没有办法在继续,需要重新下载!
@interface ViewController ()
/** 全局网络会话 - 管理所有的网络请求 */
@property (nonatomic, strong) NSURLSession *session;
@property (weak, nonatomic) IBOutlet UIProgressView *progressView;
// 下载任务
@property (nonatomic, strong) NSURLSessionDownloadTask *downloadTask;
// 续传数据
@property (nonatomic, strong) NSData *resumeData;
@end
@implementation ViewController
// 开始下载
- (IBAction)start {
// 1. url
NSURL *url = [NSURL URLWithString:@"http://localhost:8080/123.mp4"];
// 2. 开始下载
self.downloadTask = [self.session downloadTaskWithURL:url];
[self.downloadTask resume];
}
// 暂停下载
- (IBAction)pause {
NSLog(@"暂停");
// 一旦暂停,就不需要再次被暂停,否则 resumeData 就是 nil
// 在 OC 中,可以在运行时给nil发送任何消息,但是不会执行,也不会报错!
[self.downloadTask cancelByProducingResumeData:^(NSData *resumeData) {
NSLog(@"%tu", resumeData.length);
// 保存续传数据
self.resumeData = resumeData;
// 释放下载任务,防止被再次暂停
self.downloadTask = nil;
}];}
// 继续下载
- (IBAction)resume {
// 需要防止下载任务重复被创建!
if (self.resumeData == nil) {
NSLog(@"没有续传数据!");
return; }
// 使用续传数据创建下载任务 - 一旦使用续传数据新建了下载任务,续传就没用了!
self.downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];
[self.downloadTask resume];
// 释放续传数据
self.resumeData = nil;}
//mark -
// 下载完成 iOS 8.0 必须实现
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
NSLog(@"!!!%@ %@", location, [NSThread currentThread]);}
// 续传的方法,iOS 7.0 必须实现,在 iOS 8.0 可选
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes {
NSLog(@"%s", __FUNCTION__);}
// 进度的方法,iOS 7.0 必须实现,在 iOS 8.0 可选
/**
bytesWritten 本次下载字节数
totalBytesWritten 已经下载字节数
totalBytesExpectedToWrite 总下载字节数
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
float progress = (float) totalBytesWritten / totalBytesExpectedToWrite;
NSLog(@"%f %@", progress, [NSThread currentThread]);
dispatch_async(dispatch_get_main_queue(), ^{
self.progressView.progress = progress;
});}
// MARK: - 懒加载
- (NSURLSession *)session {
if (_session == nil) {
// 会话配置,可以配置全局的网络会话属性:包括:身份验证,访问超时,cookie,安全...
// 一经设置,全局共享!
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
/**
代理的工作队列
nil - 异步回调 和 实例化一个 操作队列的效果是一样的!
[[NSOperationQueue alloc] init] - 异步回调
- 注意:下载本身的线程"只有一条"
- 代理回调可以在"多个线程"回调!
[NSOperationQueue mainQueue] - 主队列回调
提示:
- 下载本身就是异步执行的,和 NSURLConnection 是一样的
- 指定代理执行的队列,不会影响到下载本身的执行
- NSURLSession 即使在主线程回调也不会造成阻塞
如何选择队列?
- 如果执行完毕后,没有复杂的操作,可以指定主队列,可以不用考虑线程间通讯!
*/
_session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
}
return _session;}
@end