iOS SDWebImage

SDWebImage

一、取消之前的下载操作

注:用一个 NSMapTable<NSString *, id>类型的属性保存下载操作,map 中一个 NSString 类型的key 对应一个 下载操作。

根据 key 查找到之前的 operation,然后取消这个 operation,再把这个operation从maptable中移除。

//生成key
NSString *validOperationKey = operationKey ?: NSStringFromClass([self class]);
//取消旧的下载操作
[self sd_cancelImageLoadOperationWithKey:validOperationKey];

sd_cancelImageLoadOperationWithKey: 方法

- (void)sd_cancelImageLoadOperationWithKey:(nullable NSString *)key {
    if (key) {
        // Cancel in progress downloader from queue
        /*
          //SDOperationsDictionary:typedef NSMapTable<NSString *, id<SDWebImageOperation>> SDOperationsDictionary;
        */
        SDOperationsDictionary *operationDictionary = [self sd_operationDictionary];
        id<SDWebImageOperation> operation;
        
        @synchronized (self) {
            operation = [operationDictionary objectForKey:key];
        }
        if (operation) {
            if ([operation conformsToProtocol:@protocol(SDWebImageOperation)]) {
                //取消
                [operation cancel];
            }
            @synchronized (self) {
                //移除
                [operationDictionary removeObjectForKey:key];
            }
        }
    }
}
二、设置占位图

如果option != SDWebImageDelayPlaceholder 设置占位图。

三、重置进度条
// reset the progress
self.sd_imageProgress.totalUnitCount = 0;
self.sd_imageProgress.completedUnitCount = 0;
四、加载图片

SDWebImageManager(单例) 负责根据 url 加载图片,首先调用 SDWebImageManager 中的 loadImageWithUrl: 方法加载图片,然后把当前加载图片的 operation 加入到 operationDictionary 中。

//manager(SDWebImageManager) 调用 loadImageWithUrl: 方法
id <SDWebImageOperation> operation = [manager loadImageWithURL:url options:options progress:combinedProgressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
    //这里是设置图片相关的代码。
    // ...
}
//把当前加载图片的 operation 加入到 operationDictionary 中
[self sd_setImageLoadOperation:operation forKey:validOperationKey];
SDWebImageManager(loadImageWithUrl:)方法

SDWebImageManager 用一个 NSMutableSet 类型的属性 failedURLs 存储所有请求失败的URL,加载图片之前先判断当前 URL 是否在 failedURLs 中,如果不在 failedURLs 中,继续向下执行。


用一个 NSMutableSet(NSMutableSet<SDWebImageCombinedOperation *>)类型的属性 runningOperations 存放所有在执行的 operation。开始加载之前需要把 当前图片下载操作添加到 runningOperations 中。

LOCK(self.runningOperationsLock);
[self.runningOperations addObject:operation];
UNLOCK(self.runningOperationsLock);
  1. 根据图片 URL 生成key;
NSString *key = [self cacheKeyForURL:url];
  1. 根据 key 从本地查找图片;

    SDImageCache 管理图片存取。调用 SDImageCache 的 queryCacheOperationForKey: 方法根据 key 从本地查找图片。
  • 首先从内存中查找
// First check the in-memory cache...
UIImage *image = [self imageFromMemoryCacheForKey:key];
  • 磁盘中查找
/从磁盘中查找
NSData *diskData = [self diskImageDataBySearchingAllPathsForKey:key];
//如果查找到,将这个图片加入到内存中
[self.memCache setObject:diskImage forKey:key cost:cost];
  1. 下载图片
  • 判断是否要下载图片:没有设置 SDWebImageFromCacheOnly(只从本地缓存中获取) && (没有从本地查找到当前 url 对应的图片 || 设置了 SDWebImageRefreshCached):
BOOL shouldDownload = (!(options & SDWebImageFromCacheOnly))
            && (!cachedImage || options & SDWebImageRefreshCached)
            && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url]);
  • 下载图片

    如果 shouldDownload == YES,调用 SDWebImageDownloader 下载图片。
a.下载成功

如果设置 SDWebImageRetryFailed == YES(默认是YES), 需要把当前 URL 从 failedURLs 中移除。

if ((options & SDWebImageRetryFailed)) {
    LOCK(self.failedURLsLock);
    [self.failedURLs removeObject:url];
    UNLOCK(self.failedURLsLock);
}

调用 SDImageCache 把下载好的图片添加内存中,如果没有设置 SDWebImageCacheMemoryOnly,磁盘中也会缓存一份。

//SDImageCache
 - (void)storeImage:(nullable UIImage *)image
         imageData:(nullable NSData *)imageData
            forKey:(nullable NSString *)key
            toDisk:(BOOL)toDisk
        completion:(nullable SDWebImageNoParamsBlock)completionBlock {
    //...
    // if memory cache is enabled
    if (self.config.shouldCacheImagesInMemory) {
        ...
        //缓存到内存中,NSData
        [self.memCache setObject:image forKey:key cost:cost];
    }
    
    if (toDisk) {//写入磁盘
        //write to disk
    }
    //...
}
内存存储

- (void)setObject:(id)obj forKey:(id)key cost:(NSUInteger)g {
    //...
    if (key && obj) {
        // Store weak cache
        LOCK(self.weakCacheLock);
        [self.weakCache setObject:obj forKey:key];
        /*
        weakCache 属性:
        NSMapTable<KeyType, ObjectType> *weakCache;
                  <NSString* key,NSData* image>
        */
        UNLOCK(self.weakCacheLock);
    }
}
磁盘存储
- (void)_storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key {
    //...
    NSString *cachePathForKey = [self defaultCachePathForKey:key];
    // transform to NSUrl
    //生成存储路径
    NSURL *fileURL = [NSURL fileURLWithPath:cachePathForKey];
    //写入磁盘
    [imageData writeToURL:fileURL options:self.config.diskCacheWritingOptions error:nil];
    //...
}
b.下载失败

如果下载失败,将当前请求失败的 URL 添加到failedURLsLock中

LOCK(self.failedURLsLock);
[self.failedURLs addObject:url];
UNLOCK(self.failedURLsLock);
下载图片的请求完成后将当前 operation 从 runningOperationsLock 中移除
LOCK(self.runningOperationsLock);
[self.runningOperations removeObject:operation];
UNLOCK(self.runningOperationsLock);
五、设置图片

加载完成后,在 loadImageWithUrl: 的回调 block 中更新进度条,设置图片。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值