iOS学习----------SDWebImage框架解析(1)

和和裕
2023-12-01

1、SDWebImage简单使用

先看demo中的例子,我们从例子出发解析SDWebImage.

[cell.imageView sd_setImageWithURL:[NSURLURLWithString:[_objectsobjectAtIndex:indexPath.row]]
                      placeholderImage:[UIImageimageNamed:@"placeholder"]options:indexPath.row ==0 ? SDWebImageRefreshCached : 0];
这个我就不多解释了,直接看这个方法的调用
@implementation UIImageView (WebCache)
...
-(void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options
...
这个方法就是为UIImageView中添加category,继续向里查看

- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock {
    
1、    [selfsd_cancelCurrentImageLoad];
    
    objc_setAssociatedObject(self, &imageURLKey, url,OBJC_ASSOCIATION_RETAIN_NONATOMIC);

   SDWebImageDelayPlaceholder图片在下载过程中的imageView将现实placeholder,表示图片下载的状态
dispatch_main_async_safe宏:如果当前是主线程就在主线程操作block 如果不是主线程就切换到主线程操作block
    if (!(options &SDWebImageDelayPlaceholder)) { 
        dispatch_main_async_safe(^{
            self.image = placeholder;
        });
    }
    
    if (url) {

        // check if activityView is enabled or not
是否需要显示菊花控件,如果需要就添加
        if ([selfshowActivityIndicatorView]) {
            [selfaddActivityIndicator];
        }

        __weak __typeof(self)wself =self;
        id <SDWebImageOperation> operation = [SDWebImageManager.sharedManagerdownloadImageWithURL:urloptions:options progress:progressBlockcompleted:^(UIImage *image,NSError *error, SDImageCacheType cacheType,BOOL finished,NSURL *imageURL) {
移除菊花控件
            [wself removeActivityIndicator];
            if (!wself) return;
            dispatch_main_sync_safe(^{
                if (!wself) return;
如果图片下载完成,并且状态 需要对图片进行处理(模糊、滤镜等),用SDWebImageAvoidAutoSetImage 调用这个completedBlock
                if (image && (options & SDWebImageAvoidAutoSetImage) && completedBlock)
                {
                    completedBlock(image, error, cacheType, url);
                    return;
                }
图片下载完成对imageView设置图片
                else if (image) { 
                    wself.image = image;
刷新界面
                    [wself setNeedsLayout];
已经从网络获取图片但是没有成功那么加载placeholder
                } else {
                    if ((options & SDWebImageDelayPlaceholder)) {
                        wself.image = placeholder;
                        [wself setNeedsLayout];
                    }
                }
图片下载完成后调用的block
                if (completedBlock && finished) {
                    completedBlock(image, error, cacheType, url);
                }
            });
        }];

封装成的opration放入到sd_setImageLoadOperation下面会有对sd_setImageLoadOperation的解释
        [selfsd_setImageLoadOperation:operationforKey:@"UIImageViewImageLoad"];
    } else {
        dispatch_main_async_safe(^{
            [selfremoveActivityIndicator];
            if (completedBlock) {
                NSError *error = [NSErrorerrorWithDomain:SDWebImageErrorDomaincode:-1userInfo:@{NSLocalizedDescriptionKey :@"Trying to load a nil url"}];
                completedBlock(nil, error, SDImageCacheTypeNone, url);
            }
        });
    }
}



这就是这个方法里面的完整代码,我们一句一句来解释

[self sd_cancelCurrentImageLoad]
******************************************
按字面意思就是取消掉当前正在下载的operation,这个方法其实就是调用的
    [selfsd_cancelImageLoadOperationWithKey:@"UIImageViewImageLoad"];源码
- (void)sd_cancelImageLoadOperationWithKey:(NSString *)key {
    // Cancel in progress downloader from queue
    NSMutableDictionary *operationDictionary = [selfoperationDictionary];
    id operations = [operationDictionary objectForKey:key];
    if (operations) {
        if ([operations isKindOfClass:[NSArray class]]) {
            for (id <SDWebImageOperation> operationin operations) {
                if (operation) {
                    [operation cancel];
                }
            }
        } else if ([operationsconformsToProtocol:@protocol(SDWebImageOperation)]){
            [(id<SDWebImageOperation>) operationscancel];
        }
        [operationDictionary removeObjectForKey:key];
    }
}


先获取operation序列,就是一个字典[self operationDictionary]
- (NSMutableDictionary *)operationDictionary {
    NSMutableDictionary *operations =objc_getAssociatedObject(self, &loadOperationKey);
    if (operations) {
        return operations;
    }
    operations = [NSMutableDictionary dictionary];
    objc_setAssociatedObject(self, &loadOperationKey, operations,OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    return operations;
}
**关于objc_getAssociatedObject和objc_setAssociatedObject的使用请转我的博客

通过key值获取到的是operations数组 然后遍历所有的operation进行取消 然后将key从字典中移除

*********************************************************

sd_setImageLoadOperation
**************************************
- (void)sd_setImageLoadOperation:(id)operation forKey:(NSString *)key {
取消下载并移除operation同上面的一样
    [selfsd_cancelImageLoadOperationWithKey:key];
获取operation字典序列
   NSMutableDictionary *operationDictionary = [selfoperationDictionary];
将当前的operation添加到序列中
    [operationDictionarysetObject:operationforKey:key];
}

**************************************





 类似资料: