SDWebImage 源码解析

下面我直接把 SDWebImage 源码里的主要类/协议逐个拆开(职责、关键属性/方法、线程/性能要点、常见扩展点 / 可定制点、源码文件位置提示),按你想读源码时最需要的顺序来写。为保证准确性,我参考了 SDWebImage 官方仓库和文档(我会在段落后加来源引用)。

参考(快捷入口):SDWebImage 官方仓库与文档。(GitHub)

先给出“总体模块图(代码角度)” — 你读源码时的地图

  • UIImageView+WebCache(UI 层封装) → 调用 → SDWebImageManager(协调器)

  • SDWebImageManager 依赖两个核心引擎:SDImageCache(缓存层) + SDWebImageDownloader / loaders(下载/加载层)

  • SDImageCache 内部又分为:内存缓存(NSCache 或自定义) + 磁盘缓存(文件 + 元数据) + CacheConfig + Serializer

  • SDWebImageDownloader 由并发下载队列 + SDWebImageDownloaderOperation 组成(支持请求合并、取消、优先级)

  • SDWebImageCodersManager / Coder plugins 负责解码/编码(支持 WebP、AVIF、GIF 等插件化 coder)

  • 额外:LoadersManager(多来源加载,如:Photos、Data、URLSession)、Transformers(图片后处理)、Transition(过渡动画)、Options/Context(配置扩展点)。(sdwebimage.github.io)


1) UIImageView+WebCache / UIButton+WebCache(类别扩展)

职责

  • 最方便的入口:把业务层的 imageView.sd_setImageWithURL: 映射到 SDWebImageManager 去执行加载逻辑。

  • 处理占位图、失败回调、取消、占位动画、setImage 的主线程更新等。

关键方法 / 文件

  • - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:... options:... context:... completed:...(文件:UIImageView+WebCache.m

实现要点

  • 创建并持有一个 SDWebImageCombinedOperation(代表单个加载任务,可以取消)。

  • 把调用上下文(options + context)传给 manager;将最终 UI 更新放在主线程。

可扩展点

  • 可以通过 sd_setImage 的 context 传入自定义 transformer、transition、加载优先级等。(sdwebimage.github.io)

2) SDWebImageManager(协调器 / 核心入口)

职责

  • 决策流程的“大管家”:先查内存缓存 → 再查磁盘 → 最后发起下载/加载。

  • 维护正在进行的加载任务去重(同 URL 多个请求合并)并分发回调。

  • 暴露公共 API 给 UI 层和其他调用方。(sdwebimage.github.io)

关键属性

  • imageCache(SDImageCache)

  • imageLoaderdownloader(SDWebImageDownloader 或 SDImageLoadersManager)

  • delegate(可选,影响缓存 key、transform 等)

  • cacheKeyFiltercacheSerializer(用于自定义 key 或如何写入磁盘)

关键方法

  • - (id<SDWebImageOperation>)loadImageWithURL:options:context:progress:completed:

    • 返回一个可取消的 operation(通常是 SDWebImageCombinedOperation

    • 内部流程:构建 cacheKey → 内存查找 → 磁盘查找(异步)→ 如果没有则委托给 loader/downloader → 解码(coders)→ 缓存写入 → 完成回调。

线程/性能要点

  • 磁盘读写与解码都在后台线程中做,主线程只负责最终回调。

  • 支持把解码后的图片直接放到内存缓存以避免下一次再次解码(性能关键)。(sdwebimage.github.io)

可扩展点 / 常见改造

  • 你可以替换 imageCacheimageLoader 实现来自定义存储或加载策略(例如从本地相册 Photos 加载)。

  • delegate/context 可用于对同一 URL 不同的处理(不同 transform 和不同缓存 key)。(sdwebimage.github.io)


3) SDImageCache(缓存层)

职责

  • 提供内存缓存 + 磁盘缓存的统一接口。负责缓存写入、读取、清理、容量策略等。

关键文件 / 类

  • SDImageCache.h/.m(核心实现)

  • SDImageCacheConfig(缓存配置)

  • SDImageCache 内部通常使用 NSCache 做内存缓存、使用文件系统 (disk cache) 做磁盘存储,磁盘通常按 namespace 存放,key 常用 URL 的 MD5 或由 cacheKeyFilter 转换。(sdwebimage.github.io)

重要方法

  • - (void)storeImage:imageData:forKey:toDisk:completion:

  • - (void)diskImageForKey:completion:(异步)

  • - (UIImage *)imageFromMemoryCacheForKey:(同步)

  • 清理方法 clearMemory, clearDisk,按年龄/大小自动清理(LRU 风格)

设计细节 / 性能点

  • 磁盘写入通常会把原始下载数据和/或编码后的形式保存,某些情况下会保存解码后的位图数据或缩略图以加速加载。

  • 内存缓存容量按像素或字节计算,并用 NSCache 自动回收(配合系统内存压力通知)。

  • 支持自定义 cacheSerializer(决定写磁盘时以什么格式存)和 cacheKeyFilter(决定 key)。(sdwebimage.github.io)


4) SDWebImageDownloader & SDWebImageDownloaderOperation(下载层)

职责

  • 负责把网络图片数据从远端拉下来(或从其他资源加载),支持队列并发、优先级、超时、HTTP 头(Etag/If-Modified-Since)、请求合并/去重、取消、进度回调等。(GitHub)

关键类/文件

  • SDWebImageDownloader.h/.m(管理下载队列、配置并发)

  • SDWebImageDownloaderOperation.h/.m(每个 URL 的实际 NSOperation,实现取消/优先级/进度/回调合并)

实现要点

  • SDWebImageDownloader 持有一个 NSOperationQueue,每个下载请求对应一个 SDWebImageDownloaderOperation

  • 请求去重:当多个请求相同 URL 到达时,会复用同一个 Operation,并把多个 completionBlock 存在 operation 里,下载完成后遍历回调(减少重复请求)。

  • 支持 maxConcurrentDownloadsdownloadTimeout 等。

  • 可自定义 sessionConfiguration,支持后台下载等场景。

常见坑 / 注意

  • 取消机制要在各方(UIImageView、manager、downloader)都能合力生效;SD 的 CombinedOperation 用来聚合取消。

  • HTTP 缓存头配合磁盘缓存可以减少流量(Etag/Last-Modified 处理通常在 downloader/operation 中)。(GitHub)


5) SDWebImageCombinedOperation / SDWebImageOperation(任务表示层)

职责

  • 表示一次“复合”加载任务(可能包含磁盘读取 + 网络下载)。支持统一的取消接口。

关键点

  • 对外返回一个 id<SDWebImageOperation>(有 cancel 方法),UI 层持有它用于取消(例如在 UITableViewCell 重用时)。

  • 内部实现会把 disk I/O task 与 network operation 都关联在一起;cancel 会同时取消所有子任务。


6) SDImageCoder / SDImageCodersManager(解码/编码层)

职责

  • 解码 NSData → UIImage、以及编码 UIImage → NSData。支持图片格式插件(WebP、AVIF、GIF 动画、HEIC 等)。

  • SDImageCodersManager 充当多个 coder 的组合管理器:按照优先级选择合适的 coder 来 decode/encode。(GitHub)

关键方法

  • - (UIImage *)decodedImageWithData:(NSData *)data options:(NSDictionary *)options;

  • - (NSData *)encodedDataWithImage:(UIImage *)image format:... options:...;

实现要点

  • 解码通常分为:解析容器(是否为 animated frames)→ 使用 ImageIO / libwebp / custom impl 解码 → 如果需要做 decompress(解码成位图),会在子线程做以避免主线程卡顿。

  • 插件化:例如 WebP 被分离到 SDWebImageWebPCoder 仓库,作为可选依赖。(GitHub)


7) SDImageLoadersManager & Loaders(加载器抽象)

职责

  • 抽象化“从某处加载图片数据”的能力,不只限于网络(例如:Photos 框架、data URI、本地 file、asset catalog 等)。

  • SDImageLoadersManager 会按顺序尝试多个 loader(支持插件)。

接口 / 设计

  • Loader 协议定义:canRequestImageForURL:requestImageWithURL:options:context:progress:completed: 等。

  • 这让 SDWebImage 能被扩展用于更多来源。(sdwebimage.github.io)


8) Transformers / Context / Options(变换与配置)

职责

  • Transformer:对 UIImage 做后处理(裁剪、圆角、模糊、缩放等),并且可以把变换后的结果单独缓存(通过变换 key 来分隔)。

  • Options/Context:运行时可传的字典,用于配置解码选项、优先级、是否只从缓存读取、缓存策略、自定义 cache key、transition 配置等。

实现要点

  • Transformer 需要提供一个唯一 key,作为缓存二次区分(即同 URL + 不同 transform 视为不同缓存条目)。

  • Context 支持传入 coder、transformer、imageScaleFactor、animatedImageClass 等。(sdwebimage.github.io)


9) SDWebImageTransition(过渡动画)

职责

  • 为图像替换提供内置/可定制的过渡,像淡入、交叉溶解等。过渡仅在主线程执行并与 UIImageView 的 setImage 结合。

关键点

  • 过渡可以是自定义的动画 block,允许在 image 设置前后做动画。(sdwebimage.github.io)

10) 辅助类 / 工具类(若干)

  • SDWebImageDownloaderOperation(上面已讲)

  • SDMemoryCache / SDImageCache 的内部 helper(比如 metadata 读写、文件名 MD5 计算)

  • SDImageCacheKeyFilterSDImageCacheSerializer(接口,用于自定义 key / 磁盘序列化)

  • SDWebImagePrefetcher(预取器:批量下载并缓存)

  • SDWebImagePlayAnimatedImage / AnimatedImageView(支持多帧动画展示的视图或插件)


常见源码热点(你打开文件时应该优先看的地方)

  1. UIImageView+WebCache.m:看请求如何构造,如何取消,以及如何包装 completion。

  2. SDWebImageManager.m:核心流程(memory → disk → loader),和任务合并逻辑。

  3. SDImageCache.m:磁盘写入策略、key 生成、LRU 清理策略。

  4. SDWebImageDownloader.m & SDWebImageDownloaderOperation.m:并发/合并/取消/HTTP 缓存处理。

  5. SDImageCodersManager.m / SDImageIOCoder.m:解码实现(注意异步解码线程池)。

  6. SDImageLoadersManager + 各种 loader(Photos、APNG、Data 等)。

这些文件通常位于仓库 SDWebImageSDWebImage 子目录下;插件如 WebP 在 SDWebImageWebPCoder 仓库中。(GitHub)


对源码阅读的建议(实践技巧)

  • 先从 UIImageView+WebCache 跟进调用链到 SDWebImageManager,把一个完整请求的生命周期走一遍(在断点或打印下)。

  • 关注 CombinedOperation 的 cancel:重用环境(表格/集合视图)里这是最容易出问题的地方。

  • 找到磁盘缓存的写入点,查看它如何处理原始 NSData 与编码后的数据(这决定磁盘缓存的大小与 IO)。

  • 看解码是在哪个队列做的(ImageIO / custom coder),测量主线程是否会被解码占用。

  • 如果你关心新格式(WebP/AVIF),查看对应 plugin 的 coder 源码(通常是独立仓库)。(GitHub)


小结(回顾要点)

  • SDWebImage 的源码是典型的职责分离 + 插件化:Manager、Cache、Downloader、Coder、Loader、Transformer 等模块都相对独立,可替换/扩展。(sdwebimage.github.io)

  • 性能关键点在于:内存缓存(解码后位图)+ 磁盘缓存(避免重复下载)+ 异步解码(避免主线程卡顿)+ 下载去重与并发控制。(GitHub)


©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容