SDWebImage 简单源码分析

248 阅读2分钟

好的,下面我们将更详细地分析 SDWebImage 的源码,结合关键代码段来深入了解其设计和实现。

1. SDWebImageManager

SDWebImageManager 是整个库的核心类,负责管理图片的下载和缓存。

核心方法 loadImageWithURL:options:progress:completed:

- (nullable SDWebImageCombinedOperation *)loadImageWithURL:(nullable NSURL *)url
                                                   options:(SDWebImageOptions)options
                                                  progress:(nullable SDImageLoaderProgressBlock)progressBlock
                                                 completed:(nullable SDInternalCompletionBlock)completedBlock {
    // 校验 URL
    if (!url || !completedBlock) {
        if (completedBlock) {
            completedBlock(nil, nil, SDImageCacheTypeNone, NSURLResponse *response, SDWebImageErrorInvalidURL, YES, url);
        }
        return nil;
    }
    
    // 创建一个 operation 对象
    __block SDWebImageCombinedOperation *operation = [SDWebImageCombinedOperation new];
    __weak SDWebImageCombinedOperation *weakOperation = operation;
    
    // 获取缓存的 key
    NSString *key = [self cacheKeyForURL:url];
    
    // 查询缓存
    operation.cacheOperation = [self.imageCache queryImageForKey:key
                                                        options:options
                                                        context:context
                                                      completion:^(UIImage * _Nullable cachedImage, NSData * _Nullable cachedData, SDImageCacheType cacheType) {
        // 如果缓存命中,则直接调用完成回调并返回
        if (cachedImage) {
            [self callCompletionBlockForOperation:weakOperation
                                          completion:completedBlock
                                             image:cachedImage
                                              data:cachedData
                                             error:nil
                                          cacheType:cacheType
                                           finished:YES
                                               url:url];
            [self safelyRemoveOperationFromRunning:operation];
            return;
        }
        
        // 如果缓存没有命中,则进行下载
        // ...
    }];
    
    return operation;
}

2. SDWebImageDownloader

SDWebImageDownloader 使用 NSURLSession 进行图片的下载。

核心方法 downloadImageWithURL:options:progress:completed:

- (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url
                                                   options:(SDWebImageDownloaderOptions)options
                                                  progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
                                                 completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock {
    // 校验 URL
    if (!url) {
        if (completedBlock) {
            completedBlock(nil, nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadURL userInfo:nil]);
        }
        return nil;
    }
    
    // 创建一个下载操作
    SDWebImageDownloaderOperation *operation = [[SDWebImageDownloaderOperation alloc] initWithRequest:request];
    
    // 配置下载操作的回调
    operation.progressBlock = progressBlock;
    operation.completedBlock = completedBlock;
    
    // 将下载操作添加到队列中
    [self.downloadQueue addOperation:operation];
    
    return operation;
}

3. SDImageCache

SDImageCache 负责图片的缓存管理,包含内存缓存和磁盘缓存。

核心方法 queryImageForKey:options:completion:

- (nullable NSOperation *)queryImageForKey:(nullable NSString *)key
                                   options:(SDImageCacheOptions)options
                                 completion:(nullable SDImageCacheCompletionBlock)completionBlock {
    if (!key) {
        if (completionBlock) {
            completionBlock(nil, nil, SDImageCacheTypeNone);
        }
        return nil;
    }
    
    // 首先查询内存缓存
    UIImage *image = [self.memoryCache objectForKey:key];
    if (image) {
        if (completionBlock) {
            completionBlock(image, nil, SDImageCacheTypeMemory);
        }
        return nil;
    }
    
    // 如果内存缓存没有命中,则查询磁盘缓存
    NSOperation *operation = [self.diskCache queryDiskCacheForKey:key done:^(UIImage * _Nullable diskImage, NSData * _Nullable data) {
        if (completionBlock) {
            completionBlock(diskImage, data, SDImageCacheTypeDisk);
        }
    }];
    
    return operation;
}

4. UIImageView+WebCache

这个分类为 UIImageView 提供了方便的方法来加载网络图片。

核心方法 sd_setImageWithURL:placeholderImage:options:progress:completed:

- (void)sd_setImageWithURL:(nullable NSURL *)url
          placeholderImage:(nullable UIImage *)placeholder
                   options:(SDWebImageOptions)options
                  progress:(nullable SDImageLoaderProgressBlock)progressBlock
                 completed:(nullable SDInternalCompletionBlock)completedBlock {
    // 取消当前的图像加载
    [self sd_cancelCurrentImageLoad];
    
    // 设置占位图
    self.image = placeholder;
    
    if (url) {
        // 使用 SDWebImageManager 加载图片
        __weak typeof(self) wself = self;
        id <SDWebImageOperation> operation = [self.sd_imageManager loadImageWithURL:url
                                                                            options:options
                                                                           progress:progressBlock
                                                                          completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
            if (!wself) return;
            dispatch_main_async_safe(^{
                if (!wself) return;
                if (image) {
                    wself.image = image;
                    [wself setNeedsLayout];
                }
                if (completedBlock && finished) {
                    completedBlock(image, data, error, cacheType, finished, imageURL);
                }
            });
        }];
        
        // 将操作与 UIImageView 绑定
        [self sd_setImageLoadOperation:operation forKey:@"UIImageViewImageLoad"];
    }
}

总结

通过源码分析,可以看出 SDWebImage 采用了模块化的设计,每个组件职责明确。SDWebImageManager 负责管理图片的下载和缓存,SDWebImageDownloader 进行图片的下载操作,SDImageCache 负责图片的缓存管理,而 UIImageView+WebCache 则提供了便捷的接口供开发者调用。

这种设计使得 SDWebImage 不仅易于使用,而且便于维护和扩展。开发者可以根据需要自定义缓存策略、下载选项等,从而灵活地处理各种图片加载需求。