SDWebImage源码解读(四)UIView+WebCache

咱们开始看UIView+WebCache

.h

1 typedef void(^SDSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable imageData);

定义一个指定参数和返回值类型的block

- (nullable NSURL *)sd_imageURL;

这也是一个get方法,获取当前视图正在请求的imageUrl

 1 /**
 2  * Set the imageView `image` with an `url` and optionally a placeholder image.
 3  *
 4  * The download is asynchronous and cached.
 5  *
 6  * @param url            The url for the image.
 7  * @param placeholder    The image to be set initially, until the image request finishes.
 8  * @param options        The options to use when downloading the image. @see SDWebImageOptions for the possible values.
 9  * @param operationKey   A string to be used as the operation key. If nil, will use the class name
10  * @param setImageBlock  Block used for custom set image code
11  * @param progressBlock  A block called while image is downloading
12  *                       @note the progress block is executed on a background queue
13  * @param completedBlock A block called when operation has been completed. This block has no return value
14  *                       and takes the requested UIImage as first parameter. In case of error the image parameter
15  *                       is nil and the second parameter may contain an NSError. The third parameter is a Boolean
16  *                       indicating if the image was retrieved from the local cache or from the network.
17  *                       The fourth parameter is the original image url.
18  */
19 - (void)sd_internalSetImageWithURL:(nullable NSURL *)url
20                   placeholderImage:(nullable UIImage *)placeholder
21                            options:(SDWebImageOptions)options
22                       operationKey:(nullable NSString *)operationKey
23                      setImageBlock:(nullable SDSetImageBlock)setImageBlock
24                           progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
25                          completed:(nullable SDExternalCompletionBlock)completedBlock;

我们来看这个UIView+WebCache对外的请求图片的接口,我们来详细解读他的参数:

①url不必说了,大家都懂。

② @param placeholder    The image to be set initially, until the image request finishes.占位图,大家都懂。

③@param options     The options to use when downloading the image. @see SDWebImageOptions for the possible values.这个是下载图片时的选项,存在于SDWebImageManager类中,是一个位移枚举,那么这个枚举每一个选项的意义,我们到SDWebImageManager中再详细研究,这里我们只需要知道它的作用,它是用来操作图片下载的细节的~嗯哼~

④@param operationKey   A string to be used as the operation key. If nil, will use the class name.这个是一个标识用的字符串,如果是nil,则默认是类名。

⑤@param setImageBlock  Block used for custom set image code.这个block使用来自定义设置图片的block,可以为nil,block中暴露的参数有uiimage对象和imagedata。

⑥@param progressBlock  A block called while image is downloading. @note the progress block is executed on a background queue这个block是在图片下载过程中调用的,而且这个block是在后台线程中执行的。block中暴露的参数有已图片下载的size和总size,以及图片url

⑦@param completedBlock A block called when operation has been completed.这个block在图片下载完成之后调用,由于这个block比较重要,我们附上代码细细观赏:

1 typedef void(^SDExternalCompletionBlock)(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL);

UIimage对象,加载失败错误error,缓存类型,imageurl

- (void)sd_cancelCurrentImageLoad;

取消当前图片的下载,他也是调用UIView+WebCacheOperation的方法去缓存字典中取消队列任务。

 1 #pragma mark - Activity indicator
 2 
 3 /**
 4  *  Show activity UIActivityIndicatorView
 5  */
 6 - (void)sd_setShowActivityIndicatorView:(BOOL)show;
 7 
 8 /**
 9  *  set desired UIActivityIndicatorViewStyle
10  *
11  *  @param style The style of the UIActivityIndicatorView
12  */
13 - (void)sd_setIndicatorStyle:(UIActivityIndicatorViewStyle)style;
14 
15 - (BOOL)sd_showActivityIndicatorView;
16 - (void)sd_addActivityIndicator;
17 - (void)sd_removeActivityIndicator;

这一块是添加设置移除菊花加载动画view的。这里面涉及到runtime和自动布局的知识点,我们就不讲述了。

- (void)sd_internalSetImageWithURL:(nullable NSURL *)url
                  placeholderImage:(nullable UIImage *)placeholder
                           options:(SDWebImageOptions)options
                      operationKey:(nullable NSString *)operationKey
                     setImageBlock:(nullable SDSetImageBlock)setImageBlock
                          progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
                         completed:(nullable SDExternalCompletionBlock)completedBlock {
    NSString *validOperationKey = operationKey ?: NSStringFromClass([self class]);
    [self sd_cancelImageLoadOperationWithKey:validOperationKey];
    objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    
    if (!(options & SDWebImageDelayPlaceholder)) {
        dispatch_main_async_safe(^{
            [self sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock];
        });
    }
    
    if (url) {
        // check if activityView is enabled or not
        if ([self sd_showActivityIndicatorView]) {
            [self sd_addActivityIndicator];
        }
        
        __weak __typeof(self)wself = self;
        id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager loadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
            __strong __typeof (wself) sself = wself;
            [sself sd_removeActivityIndicator];
            if (!sself) {
                return;
            }
            dispatch_main_async_safe(^{
                if (!sself) {
                    return;
                }
                if (image && (options & SDWebImageAvoidAutoSetImage) && completedBlock) {
                    completedBlock(image, error, cacheType, url);
                    return;
                } else if (image) {
                    [sself sd_setImage:image imageData:data basedOnClassOrViaCustomSetImageBlock:setImageBlock];
                    [sself sd_setNeedsLayout];
                } else {
                    if ((options & SDWebImageDelayPlaceholder)) {
                        [sself sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock];
                        [sself sd_setNeedsLayout];
                    }
                }
                if (completedBlock && finished) {
                    completedBlock(image, error, cacheType, url);
                }
            });
        }];
        [self sd_setImageLoadOperation:operation forKey:validOperationKey];
    } else {
        dispatch_main_async_safe(^{
            [self sd_removeActivityIndicator];
            if (completedBlock) {
                NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}];
                completedBlock(nil, error, SDImageCacheTypeNone, url);
            }
        });
    }
}

这个方法看起来很长,但是难度系数并不大,施主莫慌,且听我慢慢道来:

1.取消之前的队列

2.存储url

3.判断下载策略,如果下载策略不是SDWebImageDelayPlaceholder,那么先设置placeholder占位图。

4.如果url不为nil,判断是否显示菊花,然后是否添加菊花。

5.然后SDWebImageManager调用下载图片的方法,根据下载策略,操作completedBlock,进行图片相关的显示操作。

6.若url为nil,则completedBlock返回error。

👌,目前为止,这个方法也已经差不多解析完毕,这个类是利用SDWebImageManager进行图片下载。然后用UIView+WebCacheOperation进行队列缓存操作。

下一步,我们看SDWebImageManager这个类。

 

posted @ 2017-08-31 09:47  高山流水觅知音  阅读(258)  评论(0编辑  收藏  举报