@qidiandasheng
2016-09-04T08:06:55.000000Z
字数 5830
阅读 2924
第三方库
SDWebImage库里有个SDWebImageDownloaderOperation是专门用来做多线程下的图片下载操作的。我们现在来看一下这个类是怎么设计的。
我们先来看一下它是如何用的,然后再看一下它的内部结构。
在SDWebImage中的SDWebImageDownloader下载类中用到了这个SDWebImageDownloaderOperation下载操作类。
SDWebImageDownloader初始化的时候创建一个_operationClass对象。下面是代码,我这里只列出跟operation相关的一部分代码:
- (id)init {if ((self = [super init])) {//获取SDWebImageDownloaderOperation类对象_operationClass = [SDWebImageDownloaderOperation class];//设置执行的规则是FIFO(先进先出)还是LIFO(后进先出)_executionOrder = SDWebImageDownloaderFIFOExecutionOrder;//创建Operation队列_downloadQueue = [NSOperationQueue new];//设置队列的最大并发数_downloadQueue.maxConcurrentOperationCount = 6;}return self;}
- (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)urloptions:(SDWebImageDownloaderOptions)optionsprogress:(SDWebImageDownloaderProgressBlock)progressBlockcompleted:(SDWebImageDownloaderCompletedBlock)completedBlock;
url: 下载的图片的url
options: 一些下载的选项,主要涉及到下载的优先级、缓存、后台任务执行、cookie处理以认证几个方面。
progressBlock: 下载的进度block
completedBlock: 下载完成的block
return: 返回一个遵循<SDWebImageOperation>协议的SDWebImageDownloaderOperation实例对象。
下面就写几个在此函数中跟operation相关的代码:
//创建`SDWebImageDownloaderOperation`实例对象。operation = [[wself.operationClass alloc] initWithRequest:...];//是否压缩图片operation.shouldDecompressImages = wself.shouldDecompressImages;//下载凭证相关的东西if (wself.urlCredential) {operation.credential = wself.urlCredential;} else if (wself.username && wself.password) {operation.credential = [NSURLCredential credentialWithUser:wself.username password:wself.password persistence:NSURLCredentialPersistenceForSession];}//operation的优先级if (options & SDWebImageDownloaderHighPriority) {operation.queuePriority = NSOperationQueuePriorityHigh;} else if (options & SDWebImageDownloaderLowPriority) {operation.queuePriority = NSOperationQueuePriorityLow;}//加入到队列中[wself.downloadQueue addOperation:operation];//判断设置的执行规则,如果是LIFO(后进先出),那就使用addDependency方法,也就是之前最后一个添加的操作(lastAddedOperation)要依赖于最新这个添加进来的操作(operation),也就是要等最新的这个执行完了,之前那个才能执行。if (wself.executionOrder == SDWebImageDownloaderLIFOExecutionOrder) {// Emulate LIFO execution order by systematically adding new operations as last operation's dependency[wself.lastAddedOperation addDependency:operation];wself.lastAddedOperation = operation;}
public
NSURLRequest *request;
request请求
NSURLSessionTask *dataTask;
一个url下载任务
BOOL shouldDecompressImages
是否压缩图片
NSURLCredential *credential;
url凭证
SDWebImageDownloaderOptions options;
一些下载选项,主要涉及到下载的优先级、缓存、后台任务执行、cookie处理以认证几个方面。
NSInteger expectedSize;
将要下载的图片的实际大小
NSURLResponse *response;
url请求的回应
private
SDWebImageDownloaderProgressBlock progressBlock;
下载进度的回调
SDWebImageDownloaderCompletedBlock completedBlock;
下载完成的回调
SDWebImageNoParamsBlock cancelBlock;
取消的回调
BOOL executing;
是否正在执行
BOOL finished;
是否完成
NSMutableData *imageData;
图片数据
NSURLSession *ownedSession;
url连接对象
NSURLSessionTask *dataTask;
session任务
NSThread *thread;
线程
size_t width, height;
图片的宽高
UIImageOrientation orientation;
图片的方向
BOOL responseFromCached;
标记是否从URLCache缓存中读取的
里面主要就是一些上面的属性及一些变量的初始化。
- (id)initWithRequest:(NSURLRequest *)requestinSession:(NSURLSession *)sessionoptions:(SDWebImageDownloaderOptions)optionsprogress:(SDWebImageDownloaderProgressBlock)progressBlockcompleted:(SDWebImageDownloaderCompletedBlock)completedBlockcancelled:(SDWebImageNoParamsBlock)cancelBlock;
这是operation开始相关的操作
- (void)start {@synchronized (self) {//判断操作是否取消,如果取消则直接return不执行之后的请求。if (self.isCancelled) {self.finished = YES;[self reset];return;}//创建sessionNSURLSession *session = self.unownedSession;if (!self.unownedSession) {NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];sessionConfig.timeoutIntervalForRequest = 15;self.ownedSession = [NSURLSession sessionWithConfiguration:sessionConfigdelegate:selfdelegateQueue:nil];session = self.ownedSession;}//创建下载任务self.dataTask = [session dataTaskWithRequest:self.request];//标记正在执行self.executing = YES;//得到当前的线程self.thread = [NSThread currentThread];}//下载任务开始执行[self.dataTask resume];//判断是否有这个下载任务,如果有progressBlock从0开始执行,然后发送开始下载的通知。如果没有则直接completedBlock返回错误。if (self.dataTask) {if (self.progressBlock) {self.progressBlock(0, NSURLResponseUnknownLength);}dispatch_async(dispatch_get_main_queue(), ^{[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStartNotification object:self];});}else {if (self.completedBlock) {self.completedBlock(nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Connection can't be initialized"}], YES);}}
这是取消operation相关的操作
- (void)cancel {@synchronized (self) {if (self.thread) {[self performSelector:@selector(cancelInternalAndStop) onThread:self.thread withObject:nil waitUntilDone:NO];}else {[self cancelInternal];}}}- (void)cancelInternalAndStop {if (self.isFinished) return;[self cancelInternal];}- (void)cancelInternal {if (self.isFinished) return;[super cancel];if (self.cancelBlock) self.cancelBlock();if (self.dataTask) {[self.dataTask cancel];dispatch_async(dispatch_get_main_queue(), ^{[[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:self];});// As we cancelled the connection, its callback won't be called and thus won't// maintain the isFinished and isExecuting flags.if (self.isExecuting) self.executing = NO;if (!self.isFinished) self.finished = YES;}[self reset];}
这是一些重置及设置实例变量的方法
- (void)done {self.finished = YES;self.executing = NO;[self reset];}- (void)reset {self.cancelBlock = nil;self.completedBlock = nil;self.progressBlock = nil;self.dataTask = nil;self.imageData = nil;self.thread = nil;if (self.ownedSession) {[self.ownedSession invalidateAndCancel];self.ownedSession = nil;}}- (void)setFinished:(BOOL)finished {[self willChangeValueForKey:@"isFinished"];_finished = finished;[self didChangeValueForKey:@"isFinished"];}- (void)setExecuting:(BOOL)executing {[self willChangeValueForKey:@"isExecuting"];_executing = executing;[self didChangeValueForKey:@"isExecuting"];}//定义一个并发操作,重写这个方法并且返回YES- (BOOL)isConcurrent {return YES;}
然后就是一些NSURLSessionDataDelegate和NSURLSessionTaskDelegate对应的回调方法
为什么要创建SDWebImageDownloaderOperation类对象