SDWebImage源码之DownLoader

作者: _兜兜转转_ | 来源:发表于2019-04-22 15:32 被阅读0次

    SDWebImageDownloader下载器

    源码+注释:

    - (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url
                                                       options:(SDWebImageDownloaderOptions)options
                                                       context:(nullable SDWebImageContext *)context
                                                      progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
                                                     completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock {
        // The URL will be used as the key to the callbacks dictionary so it cannot be nil. If it is nil immediately call the completed block with no image or data.
        if (url == nil) {//没有url直接 执行 complateblock
            if (completedBlock) {
                NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorInvalidURL userInfo:@{NSLocalizedDescriptionKey : @"Image url is nil"}];
                completedBlock(nil, nil, error, YES);
            }
            return nil;
        }
        
        SD_LOCK(self.operationsLock);//信号量为1实现加锁 operation
        NSOperation<SDWebImageDownloaderOperation> *operation = [self.URLOperations objectForKey:url];
        //已经完成 或者取消的opertion 都被删除 则下边重新新建opertion
        if (!operation || operation.isFinished || operation.isCancelled) {
    //新建op
            operation = [self createDownloaderOperationWithUrl:url options:options context:context];
            if (!operation) {
    //如果新建op失败 则解锁 返回并执行complateblock
                SD_UNLOCK(self.operationsLock);
                if (completedBlock) {
                    NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorInvalidDownloadOperation userInfo:@{NSLocalizedDescriptionKey : @"Downloader operation is nil"}];
                    completedBlock(nil, nil, error, YES);
                }
                return nil;
            }
            @weakify(self);//weakself
            operation.completionBlock = ^{
                @strongify(self);//延迟释放self'
                if (!self) {//如果释放了 则返回
                    return;
                }
                SD_LOCK(self.operationsLock);//加锁 并删除url
                [self.URLOperations removeObjectForKey:url];
                SD_UNLOCK(self.operationsLock);
            };
            self.URLOperations[url] = operation;
            //加入到队列和字典中
            [self.downloadQueue addOperation:operation];
        }
        else if (!operation.isExecuting) {
    //重置op的优先级
            if (options & SDWebImageDownloaderHighPriority) {
                operation.queuePriority = NSOperationQueuePriorityHigh;
            } else if (options & SDWebImageDownloaderLowPriority) {
                operation.queuePriority = NSOperationQueuePriorityLow;
            } else {
                operation.queuePriority = NSOperationQueuePriorityNormal;
            }
        }
    //解锁
        SD_UNLOCK(self.operationsLock);
        
        id downloadOperationCancelToken = [operation addHandlersForProgress:progressBlock completed:completedBlock];
        //信息记录都token中 可以执行cancel操作
        SDWebImageDownloadToken *token = [[SDWebImageDownloadToken alloc] initWithDownloadOperation:operation];
        token.url = url;
        token.request = operation.request;
        token.downloadOperationCancelToken = downloadOperationCancelToken;
        token.downloader = self;
        
        return token;
    }
    //取消token
    - (void)cancel:(nullable SDWebImageDownloadToken *)token {
        NSURL *url = token.url;
        if (!url) {
            return;
        }//加锁
        SD_LOCK(self.operationsLock);
        NSOperation<SDWebImageDownloaderOperation> *operation = [self.URLOperations objectForKey:url];
        if (operation) {
    //取消下载 
            BOOL canceled = [operation cancel:token.downloadOperationCancelToken];
            if (canceled) {
                [self.URLOperations removeObjectForKey:url];
            }
        }
        SD_UNLOCK(self.operationsLock);
    }
    //取消NSOperationQueue中的所有的下载op
    - (void)cancelAllDownloads {
        [self.downloadQueue cancelAllOperations];
    }
    
    统一下载入口
    
    - (void)sd_internalSetImageWithURL:(nullable NSURL *)url
                      placeholderImage:(nullable UIImage *)placeholder
                               options:(SDWebImageOptions)options
                               context:(nullable SDWebImageContext *)context
                         setImageBlock:(nullable SDSetImageBlock)setImageBlock
                              progress:(nullable SDImageLoaderProgressBlock)progressBlock
                             completed:(nullable SDInternalCompletionBlock)completedBlock {
        context = [context copy]; // copy to avoid mutable object
        NSString *validOperationKey = context[SDWebImageContextSetImageOperationKey];
        if (!validOperationKey) {
            validOperationKey = NSStringFromClass([self class]);
        }
        self.sd_latestOperationKey = validOperationKey;
    //取消view old的下载任务
        [self sd_cancelImageLoadOperationWithKey:validOperationKey];
        self.sd_imageURL = url;
        
        if (!(options & SDWebImageDelayPlaceholder)) {
            dispatch_main_async_safe(^{
                [self sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock cacheType:SDImageCacheTypeNone imageURL:url];
            });
        }
        
        if (url) {
            // reset the progress
            self.sd_imageProgress.totalUnitCount = 0;
            self.sd_imageProgress.completedUnitCount = 0;
            
    #if SD_UIKIT || SD_MAC
            // check and start image indicator
            [self sd_startImageIndicator];
            id<SDWebImageIndicator> imageIndicator = self.sd_imageIndicator;
    #endif
            
            SDWebImageManager *manager = context[SDWebImageContextCustomManager];
            if (!manager) {
                manager = [SDWebImageManager sharedManager];
            }
            
            @weakify(self);
            SDImageLoaderProgressBlock combinedProgressBlock = ^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
                @strongify(self);
                NSProgress *imageProgress = self.sd_imageProgress;
                imageProgress.totalUnitCount = expectedSize;
                imageProgress.completedUnitCount = receivedSize;
    #if SD_UIKIT || SD_MAC
                if ([imageIndicator respondsToSelector:@selector(updateIndicatorProgress:)]) {
                    double progress = imageProgress.fractionCompleted;
                    dispatch_async(dispatch_get_main_queue(), ^{
                        [imageIndicator updateIndicatorProgress:progress];
                    });
                }
    #endif
                if (progressBlock) {
                    progressBlock(receivedSize, expectedSize, targetURL);
                }
            };
            id <SDWebImageOperation> operation = [manager loadImageWithURL:url options:options context:context progress:combinedProgressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
                @strongify(self);
                if (!self) { return; }
                // if the progress not been updated, mark it to complete state
                if (finished && !error && self.sd_imageProgress.totalUnitCount == 0 && self.sd_imageProgress.completedUnitCount == 0) {
                    self.sd_imageProgress.totalUnitCount = SDWebImageProgressUnitCountUnknown;
                    self.sd_imageProgress.completedUnitCount = SDWebImageProgressUnitCountUnknown;
                }
                
    #if SD_UIKIT || SD_MAC
                // check and stop image indicator
                if (finished) {
                    [self sd_stopImageIndicator];
                }
    #endif
                
                BOOL shouldCallCompletedBlock = finished || (options & SDWebImageAvoidAutoSetImage);
                BOOL shouldNotSetImage = ((image && (options & SDWebImageAvoidAutoSetImage)) ||
                                          (!image && !(options & SDWebImageDelayPlaceholder)));
                SDWebImageNoParamsBlock callCompletedBlockClojure = ^{
                    if (!self) { return; }
                    if (!shouldNotSetImage) {
                        [self sd_setNeedsLayout];
                    }
                    if (completedBlock && shouldCallCompletedBlock) {
                        completedBlock(image, data, error, cacheType, finished, url);
                    }
                };
                
                // case 1a: we got an image, but the SDWebImageAvoidAutoSetImage flag is set
                // OR
                // case 1b: we got no image and the SDWebImageDelayPlaceholder is not set
                if (shouldNotSetImage) {
                    dispatch_main_async_safe(callCompletedBlockClojure);
                    return;
                }
                
                UIImage *targetImage = nil;
                NSData *targetData = nil;
                if (image) {
                    // case 2a: we got an image and the SDWebImageAvoidAutoSetImage is not set
                    targetImage = image;
                    targetData = data;
                } else if (options & SDWebImageDelayPlaceholder) {
                    // case 2b: we got no image and the SDWebImageDelayPlaceholder flag is set
                    targetImage = placeholder;
                    targetData = nil;
                }
                
    #if SD_UIKIT || SD_MAC
                // check whether we should use the image transition
                SDWebImageTransition *transition = nil;
                if (finished && (options & SDWebImageForceTransition || cacheType == SDImageCacheTypeNone)) {
                    transition = self.sd_imageTransition;
                }
    #endif
                dispatch_main_async_safe(^{
    #if SD_UIKIT || SD_MAC
                    [self sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:transition cacheType:cacheType imageURL:imageURL];
    #else
                    [self sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock cacheType:cacheType imageURL:imageURL];
    #endif
                    callCompletedBlockClojure();
                });
            }];
            [self sd_setImageLoadOperation:operation forKey:validOperationKey];
        } else {
    #if SD_UIKIT || SD_MAC
            [self sd_stopImageIndicator];
    #endif
            dispatch_main_async_safe(^{
                if (completedBlock) {
                    NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:SDWebImageErrorInvalidURL userInfo:@{NSLocalizedDescriptionKey : @"Image url is nil"}];
                    completedBlock(nil, nil, error, SDImageCacheTypeNone, YES, url);
                }
            });
        }
    }
    
    

    最后放上镇楼图:


    SDWebimage的框架概览

    相关文章

      网友评论

        本文标题:SDWebImage源码之DownLoader

        本文链接:https://www.haomeiwen.com/subject/hamygqtx.html