我们通常使用单例来创建我们的下载,以便在各个类中使用,但是单例只能是唯一的,那么如何通过一个单例创建多个下载?我们可以在单例中添加一个私有的可变字典属性,将多个下载存入字典,如此,我们通过一个单例来创建多个下载任务,下面的代码,定义了有效的接口,可以很方便的在其它app中使用:
创建一个NSURLSessionDownloadTask类
//
// Download.h
// TestOfDownload
#import <Foundation/Foundation.h>
//定义block
typedef void(^finishedPath)(NSString *path, NSString *url);
typedef void(^downloading)(long long writeData, float progress);
//定义一个代理
@protocol DownloadDelegate <NSObject>
//一个一定要执行的代理, 作用: 让单例代理对象销毁下载对象
- (void)moveFinishedPathWithURL:(NSString *)url;
@end
@interface Download : NSObject<NSURLSessionDownloadDelegate>
@property (strong, nonatomic, readonly) NSString *url;//下载网址
@property (strong, nonatomic) NSURLSession *session; // 下载的支持父类
@property (strong, nonatomic) NSURLSessionDownloadTask *downloadTask;//下载;
@property (strong, nonatomic) NSMutableData *data; //保存断点下载的数据
@property (assign, nonatomic) id<DownloadDelegate>delegate;
//创建一个下载
- (instancetype)initWithURL:(NSString *)url;
//暂停接口
- (void)didSuspend;
//恢复下载接口
- (void)didResume;
//下载进度接口
- (void)didDownloading:(downloading)downloading finish:(finishedPath)finished;
@end
//
// Download.m
// TestOfDownload
#import "Download.h"
@interface Download ()
@property (copy, nonatomic) finishedPath downloadPath;//下载完成后路径
@property (copy, nonatomic) downloading downloading;//下载中数据
@end
@implementation Download
- (void)dealloc
{
_delegate = nil;
}
- (instancetype)initWithURL:(NSString *)url {
self = [super init];
if (self) {
_url = url; //赋值,readonly ,使用下划线
self.session = [NSURLSession sessionWithConfiguration:nil delegate:self delegateQueue:[NSOperationQueue mainQueue]];
self.downloadTask = [self.session downloadTaskWithURL:[NSURL URLWithString:url]];
[self.downloadTask resume];//调用父类NSURLSessionTask的重新下载方法
}
return self;
}
//暂停接口
- (void)didSuspend {
__weak typeof(self) vc = self;
[self.downloadTask cancelByProducingResumeData:^(NSData *resumeData) {
vc.data = (NSMutableData *)resumeData;
vc.downloadTask = nil;
}];
}
//恢复下载接口
- (void)didResume {
self.downloadTask = [self.session downloadTaskWithResumeData:self.data];
[self.downloadTask resume]; //调用父类的重新下载方法
self.data = nil;
}
//下载进度接口
- (void)didDownloading:(downloading)downloading finish:(finishedPath)finished {
self.downloading = downloading; //block赋值
self.downloadPath = finished;
}
#pragma mark-----实现NSURLSessionDownloadDelegate代理------
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location {
//完成下载
//下载完成后移动到的文件夹路径
NSString *cache = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
//下载完成后移动的文件路径
NSString *file = [cache stringByAppendingPathComponent:downloadTask.response.suggestedFilename];//服务器的名字
//对文件进行操作
NSFileManager *fm = [NSFileManager defaultManager];
//移动文件
[fm moveItemAtPath:location.path toPath:file error:nil];
//通过bloack,将下载网址和文件路径传出去
self.downloadPath(file,self.url);
//下载完成后执行销毁代理
if ([_delegate respondsToSelector:@selector(moveFinishedPathWithURL:)]) {
[_delegate moveFinishedPathWithURL:self.url];
}
//销毁对象,同NSTimer
[self.session invalidateAndCancel];
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
//下载中
//block传递下载的数据和进度
float progress = (float)totalBytesWritten / totalBytesExpectedToWrite;
self.downloading(bytesWritten, progress * 100.0);
}
@end
创建一个单例类:
//
// SingletonDownload.h
// TestOfDownload
#import <Foundation/Foundation.h>
#import "Download.h"
@interface SingletonDownload : NSObject<DownloadDelegate>
//创建单例
+ (instancetype)shareSingletonDownloader;
//添加一个下载
- (Download *)addDownloaderWithURL:(NSString *)url;
//根据url找到下载
- (Download *)findDownloaderWithURL:(NSString *)url;
//返回所有下载
- (NSArray *)allDownloader;
@end
//
// SingletonDownload.m
// TestOfDownload
#import "SingletonDownload.h"
@interface SingletonDownload ()
@property (strong, nonatomic) NSMutableDictionary *allDownloaderDic;//创建一个字典,用来保存当前的下载,使单例持有它,从而不会被销毁
@end
@implementation SingletonDownload
- (NSMutableDictionary *)allDownloaderDic {
if (!_allDownloaderDic) {
self.allDownloaderDic = [NSMutableDictionary dictionary];
}
return _allDownloaderDic;
}
//创建单例
+ (instancetype)shareSingletonDownloader {
static SingletonDownload *singleton = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singleton = [[SingletonDownload alloc] init];
});
return singleton;
}
//添加一个下载
- (Download *)addDownloaderWithURL:(NSString *)url {
//判断是否有下载
Download *downloader =self.allDownloaderDic[url];
downloader.delegate = self;
if (!downloader) {
downloader = [[Download alloc] initWithURL:url];
//将单例存入字典中
[self.allDownloaderDic setValue:downloader forKey:url];
}
return downloader;
}
//根据url找到下载
- (Download *)findDownloaderWithURL:(NSString *)url {
return self.allDownloaderDic[url];
}
//返回所有下载
- (NSArray *)allDownloader {
return [self.allDownloaderDic allValues];
}
#pragma mark-----代理执行----
- (void)moveFinishedPathWithURL:(NSString *)url {
//下载完成,销毁对象
[self.allDownloaderDic removeObjectForKey:url];
}
@end