SDWebImage源码解读(四)UIImageView+WebCache

前言

这三个分类比较简单,就放在一起解读了。

正文

UIImageView+WebCache

这是UIImageView的分类,旨在使用UIImageView加载图片。

我们看具体代码

 1 - (void)sd_setImageWithURL:(nullable NSURL *)url;
 2 
 3 - (void)sd_setImageWithURL:(nullable NSURL *)url
 4           placeholderImage:(nullable UIImage *)placeholder;
 5 
 6 - (void)sd_setImageWithURL:(nullable NSURL *)url
 7           placeholderImage:(nullable UIImage *)placeholder
 8                    options:(SDWebImageOptions)options;
 9 
10 - (void)sd_setImageWithURL:(nullable NSURL *)url
11                  completed:(nullable SDExternalCompletionBlock)completedBlock;
12 
13 - (void)sd_setImageWithURL:(nullable NSURL *)url
14           placeholderImage:(nullable UIImage *)placeholder
15                  completed:(nullable SDExternalCompletionBlock)completedBlock;
16 
17 - (void)sd_setImageWithURL:(nullable NSURL *)url
18           placeholderImage:(nullable UIImage *)placeholder
19                    options:(SDWebImageOptions)options
20                  completed:(nullable SDExternalCompletionBlock)completedBlock;
21 
22 - (void)sd_setImageWithURL:(nullable NSURL *)url
23           placeholderImage:(nullable UIImage *)placeholder
24                    options:(SDWebImageOptions)options
25                   progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
26                  completed:(nullable SDExternalCompletionBlock)completedBlock;
27 
28 - (void)sd_setImageWithPreviousCachedImageWithURL:(nullable NSURL *)url
29                                  placeholderImage:(nullable UIImage *)placeholder
30                                           options:(SDWebImageOptions)options
31                                          progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
32                                         completed:(nullable SDExternalCompletionBlock)completedBlock;

跳转到这几个方法的具体实现,显而易见,它们最终调用UIView+WebCache的这个方法(这个方法随后解释):

- (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;

有一个点稍微注意下:

划线的三目运算符,如果问号之后的第一个参数未填写,则默认返回条件本身。

那么接下来,这个类还有两个方法需要解读:

1 /**
2  * Download an array of images and starts them in an animation loop
3  *
4  * @param arrayOfURLs An array of NSURL
5  */
6 - (void)sd_setAnimationImagesWithURLs:(nonnull NSArray<NSURL *> *)arrayOfURLs;
7 
8 - (void)sd_cancelCurrentAnimationImagesLoad;

根据方法声明,我们了解到,这是用来加载UIImageView的帧动画图片数组。我们直接看方法的具体实现:

- (void)sd_setAnimationImagesWithURLs:(nonnull NSArray<NSURL *> *)arrayOfURLs {
    [self sd_cancelCurrentAnimationImagesLoad];
    __weak __typeof(self)wself = self;

    NSMutableArray<id<SDWebImageOperation>> *operationsArray = [[NSMutableArray alloc] init];

    for (NSURL *logoImageURL in arrayOfURLs) {
        id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager loadImageWithURL:logoImageURL options:0 progress:nil completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
            if (!wself) return;
            dispatch_main_async_safe(^{
                __strong UIImageView *sself = wself;
                [sself stopAnimating];
                if (sself && image) {
                    NSMutableArray<UIImage *> *currentImages = [[sself animationImages] mutableCopy];
                    if (!currentImages) {
                        currentImages = [[NSMutableArray alloc] init];
                    }
                    [currentImages addObject:image];

                    sself.animationImages = currentImages;
                    [sself setNeedsLayout];
                }
                [sself startAnimating];
            });
        }];
        [operationsArray addObject:operation];
    }

    [self sd_setImageLoadOperation:[operationsArray copy] forKey:@"UIImageViewAnimationImages"];
}

- (void)sd_cancelCurrentAnimationImagesLoad {
    [self sd_cancelImageLoadOperationWithKey:@"UIImageViewAnimationImages"];
}

我们可以看到,这个方法遍历图片URL数组,然后使用SDWebImageManager的方法,将每个图片加载的操作放入operation数组中,然后调用:

    [self sd_setImageLoadOperation:[operationsArray copy] forKey:@"UIImageViewAnimationImages"];

这个方法是UIView+WebCacheOperation,将所有操作用字典进行存储。

在这个方法内部,我们看到“dispatch_main_async_safe”

1 #ifndef dispatch_main_async_safe
2 #define dispatch_main_async_safe(block)\
3     if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(dispatch_get_main_queue())) == 0) {\
4         block();\
5     } else {\
6         dispatch_async(dispatch_get_main_queue(), block);\
7     }
8 #endif

这是SDWebImageCompat类中的宏定义。目的是保证线程安全,保证block中的代码在主线程中执行。当图片一旦被下载,就在主线程更新UIimageview。

- (void)sd_cancelCurrentAnimationImagesLoad {
    [self sd_cancelImageLoadOperationWithKey:@"UIImageViewAnimationImages"];
}

最后一个方法,是取消当前正在加载的AnimationImages操作

 

posted @ 2017-08-30 17:46  高山流水觅知音  阅读(931)  评论(0编辑  收藏  举报