第五篇

前言

本篇主要讲解图片缓存类的知识,虽然只涉及了图片方面的缓存的设计,但思想同样适用于别的方面的设计。在架构上来说,缓存算是存储设计的一部分。我们把各种不同的存储内容按照功能进行切割后,图片缓存便是其中的一个。

我们在封装自己的图片缓存管理对象的时候,SDWebImageCache能够提供大约90%的代码给我们直接使用,基于这些代码,我们需要分析出作者的设计思想是什么?当需要缓存某个列表时,基于SDWebImageCache的设计思想,我们就能够设计出比较合理的缓存管理对象了。

所谓举一反三就是这样的道理。

整体架构

我们不看实现文件,只看作者暴露出来的内容,来分析该类有哪些属性和方法。看完整体架构这一节,我们必须明白如何使用这个缓存管理者。具体的实现过程会在下边的实现原理一节中讲解。

1.缓存位置

图片可以被缓存到两个地方:

  • 内存
  • 硬盘

2.配置

通过SDImageCacheConfig这个类来管理缓存的配置信息,我们打开SDImageCacheConfig后,发现可以配置的东西有:

  • shouldDecompressImages 是否解压缩图片,默认为YES
  • disable iCloud backup 是否禁用iCloud备份, 默认为YES
  • shouldCacheImagesInMemory 是否缓存到内存中,默认为YES
  • maxCacheAge 最大的缓存不过期时间, 单位为秒,默认为一周的时间
  • maxCacheSize 最大的缓存尺寸,单位为字节

代码如下:

@interface SDImageCacheConfig : NSObject

/**
* Decompressing images that are downloaded and cached can improve performance but can consume lot of memory.
* Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption.
*/
@property (assign, nonatomic) BOOL shouldDecompressImages; /**
* disable iCloud backup [defaults to YES]
*/
@property (assign, nonatomic) BOOL shouldDisableiCloud; /**
* use memory cache [defaults to YES]
*/
@property (assign, nonatomic) BOOL shouldCacheImagesInMemory; /**
* The maximum length of time to keep an image in the cache, in seconds
*/
@property (assign, nonatomic) NSInteger maxCacheAge; /**
* The maximum size of the cache, in bytes.
*/
@property (assign, nonatomic) NSUInteger maxCacheSize; @end

--

static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week

@implementation SDImageCacheConfig

- (instancetype)init {
if (self = [super init]) {
_shouldDecompressImages = YES;
_shouldDisableiCloud = YES;
_shouldCacheImagesInMemory = YES;
_maxCacheAge = kDefaultCacheMaxCacheAge;
_maxCacheSize = 0;
}
return self;
} @end

3.内存最大缓存

可以通过maxMemoryCost来设置内存的最大缓存是多少,这个是以像素为单位的。

4.最大内存缓存数量

可以通过maxMemoryCountLimit来设置内存的最大缓存数量是多少。

5.初始化

一般来说,一个管理类都有一个全局的单利对象,该类也不例外,然后根据业务需求设计不同的初始化方法。不管是什么样的类,我们在设计它的时候,应该通过合理的初始化方法告诉别的开发者,该类应该如何创建

  • + (nonnull instancetype)sharedImageCache 单利
  • - (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns 通过制定的namespace来初始化
  • - (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns diskCacheDirectory:(nonnull NSString *)directory NS_DESIGNATED_INITIALIZER 指定namespacepath.

注意:如果想设置某个方法为指定的初始化方法,通过NS_DESIGNATED_INITIALIZER来实现。

6.Cache paths

既然把数据缓存到了disk中,那么就要提供一个方法获取这个缓存路径。这里通过下边这个方法,根据namespace获取缓存路径:

- (nullable NSString *)makeDiskCachePath:(nonnull NSString*)fullNamespace;

注意:在开发中,我们会遇到这样的情况,假如我之前把图片缓存到了地址1,现在我打算重构代码。写了这么一个缓存管理者,我需要和之前的缓存的图片建立联系,但是以后都打算使用新写的这个管理者,那怎么办呢??

我们想到,我只需要把之前的路径添加到管理类的路径集合中就行了。主要目的是在搜索图片的时候,也有权限去搜索新添加的路径。

我在想,一个好的架构,或框架,应该使用这用思想

这也是下边这个方法的意义:

/**
* Add a read-only cache path to search for images pre-cached by SDImageCache
* Useful if you want to bundle pre-loaded images with your app
*
* @param path The path to use for this read-only cache path
*/
- (void)addReadOnlyCachePath:(nonnull NSString *)path;

7.存储图片

我们已经说过了,图片会被存储到内存或者硬盘中,在这一存储过程的设计中有下边这几个需要考虑的因素:

  • 数据源:可以保存UIImage也可以保存NSData
  • 唯一标识:找到该数据的唯一标识,一般使用图片的URL
  • 是否需要保存到硬盘:根据配置文件中的设置,如果设置了应该缓存到内存,那么图片肯定会被缓存到内存中。
  • 数据保存这一过程必须是异步的,在完成之后,在主线程回调

代码如下:

/**
* Asynchronously store an image into memory and disk cache at the given key.
*
* @param image The image to store
* @param key The unique image cache key, usually it's image absolute URL
* @param completionBlock A block executed after the operation is finished
*/
- (void)storeImage:(nullable UIImage *)image
forKey:(nullable NSString *)key
completion:(nullable SDWebImageNoParamsBlock)completionBlock; /**
* Asynchronously store an image into memory and disk cache at the given key.
*
* @param image The image to store
* @param key The unique image cache key, usually it's image absolute URL
* @param toDisk Store the image to disk cache if YES
* @param completionBlock A block executed after the operation is finished
*/
- (void)storeImage:(nullable UIImage *)image
forKey:(nullable NSString *)key
toDisk:(BOOL)toDisk
completion:(nullable SDWebImageNoParamsBlock)completionBlock; /**
* Asynchronously store an image into memory and disk cache at the given key.
*
* @param image The image to store
* @param imageData The image data as returned by the server, this representation will be used for disk storage
* instead of converting the given image object into a storable/compressed image format in order
* to save quality and CPU
* @param key The unique image cache key, usually it's image absolute URL
* @param toDisk Store the image to disk cache if YES
* @param completionBlock A block executed after the operation is finished
*/
- (void)storeImage:(nullable UIImage *)image
imageData:(nullable NSData *)imageData
forKey:(nullable NSString *)key
toDisk:(BOOL)toDisk
completion:(nullable SDWebImageNoParamsBlock)completionBlock; /**
* Synchronously store image NSData into disk cache at the given key.
*
* @warning This method is synchronous, make sure to call it from the ioQueue
*
* @param imageData The image data to store
* @param key The unique image cache key, usually it's image absolute URL
*/
- (void)storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key;

8.获取图片

对于如何获取图片。作者给出了比较多的方式,首先考虑内存和硬盘,其次考虑异步获取还是同步获取。如果获取数据异步的,就要使用block。总结下来有这么几种情况:

  • 判断图片是否被缓存到disk(异步)

      /**
    * Async check if image exists in disk cache already (does not load the image)
    *
    * @param key the key describing the url
    * @param completionBlock the block to be executed when the check is done.
    * @note the completion block will be always executed on the main queue
    */
    - (void)diskImageExistsWithKey:(nullable NSString *)key completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock;
  • 异步查询图片是否存在,这里返回了一个NSOperation,原因是在内存中获取耗时非常短,在disk中时间相对较长。

      /**
    * Operation that queries the cache asynchronously and call the completion when done.
    *
    * @param key The unique key used to store the wanted image
    * @param doneBlock The completion block. Will not get called if the operation is cancelled
    *
    * @return a NSOperation instance containing the cache op
    */
    - (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key done:(nullable SDCacheQueryCompletedBlock)doneBlock;
  • 同步在内存查询图片

      /**
    * Query the memory cache synchronously.
    *
    * @param key The unique key used to store the image
    */
    - (nullable UIImage *)imageFromMemoryCacheForKey:(nullable NSString *)key;
  • 同步在disk查询图片

      /**
    * Query the disk cache synchronously.
    *
    * @param key The unique key used to store the image
    */
    - (nullable UIImage *)imageFromDiskCacheForKey:(nullable NSString *)key;
  • 同步查找图片,先内存后disk

      /**
    * Query the cache (memory and or disk) synchronously after checking the memory cache.
    *
    * @param key The unique key used to store the image
    */
    - (nullable UIImage *)imageFromCacheForKey:(nullable NSString *)key;

9.移除某条数据

数据可能存在于内存,也可能是disk,也可能两者都有,那么我们要想移除数据,就要考虑这些情况了。

  • 全部移除

      /**
    * Remove the image from memory and disk cache asynchronously
    *
    * @param key The unique image cache key
    * @param completion A block that should be executed after the image has been removed (optional)
    */
    - (void)removeImageForKey:(nullable NSString *)key withCompletion:(nullable SDWebImageNoParamsBlock)completion;
  • 移除内存数据,是否也移除disk数据

      /**
    * Remove the image from memory and optionally disk cache asynchronously
    *
    * @param key The unique image cache key
    * @param fromDisk Also remove cache entry from disk if YES
    * @param completion A block that should be executed after the image has been removed (optional)
    */
    - (void)removeImageForKey:(nullable NSString *)key fromDisk:(BOOL)fromDisk withCompletion:(nullable SDWebImageNoParamsBlock)completion;
  • 移除disk数据,是否也移除内存数据 这种情况SDWebImageCache未实现

10.移除数据

这个移除不同于上边的移除,它会清空所有的符合条件的数据。

  • 清空内存

      /**
    * Clear all memory cached images
    */
    - (void)clearMemory;
  • 清空disk

      /**
    * Async clear all disk cached images. Non-blocking method - returns immediately.
    * @param completion A block that should be executed after cache expiration completes (optional)
    */
    - (void)clearDiskOnCompletion:(nullable SDWebImageNoParamsBlock)completion;
  • 清空过期数据

      /**
    * Async remove all expired cached image from disk. Non-blocking method - returns immediately.
    * @param completionBlock A block that should be executed after cache expiration completes (optional)
    */
    - (void)deleteOldFilesWithCompletionBlock:(nullable SDWebImageNoParamsBlock)completionBlock;

11.获取缓存相关信息

获取缓存的相关信息:

  • 获取disk使用size

      /**
    * Get the size used by the disk cache
    */
    - (NSUInteger)getSize;
  • 获取disk缓存的图片数目

      /**
    * Get the number of images in the disk cache
    */
    - (NSUInteger)getDiskCount;
  • 异步获取disk使用size

      /**
    * Asynchronously calculate the disk cache's size.
    */
    - (void)calculateSizeWithCompletionBlock:(nullable SDWebImageCalculateSizeBlock)completionBlock;
  • 获取某个路径下的指定的图片,比如key为http://www.123.com/image.png,path为http://www.456.com,那么调用后边的方法后,返回http://www.456.com/image.png

      /**
    * Get the cache path for a certain key (needs the cache path root folder)
    *
    * @param key the key (can be obtained from url using cacheKeyForURL)
    * @param path the cache path root folder
    *
    * @return the cache path
    */
    - (nullable NSString *)cachePathForKey:(nullable NSString *)key inPath:(nonnull NSString *)path;
  • 获取默认的缓存路径

      /**
    * Get the default cache path for a certain key
    *
    * @param key the key (can be obtained from url using cacheKeyForURL)
    *
    * @return the default cache path
    */
    - (nullable NSString *)defaultCachePathForKey:(nullable NSString *)key;

总结

本来打算把实现部分也写到这篇文章的,但是现在看来不太合适,文章太长了,影响阅读体验。阅读完本篇后,我们就能够明白SDWebImageCache究竟能够给我提供哪些功能,更进一步,我们了解到设计这样一个管理者的答题思路是什么。下一篇就是该管理者的实现部分。

由于个人知识有限,如有错误之处,还望各路大侠给予指出啊

  1. SDWebImage源码解读 之 NSData+ImageContentType 简书 博客园
  2. SDWebImage源码解读 之 UIImage+GIF 简书 博客园
  3. SDWebImage源码解读 之 SDWebImageCompat 简书 博客园
  4. SDWebImage源码解读_之SDWebImageDecoder 简书 博客园

SDWebImage源码解读之SDWebImageCache(上)的更多相关文章

  1. SDWebImage源码解读之SDWebImageCache(下)

    第六篇 前言 我们在SDWebImageCache(上)中了解了这个缓存类大概的功能是什么?那么接下来就要看看这些功能是如何实现的? 再次强调,不管是图片的缓存还是其他各种不同形式的缓存,在原理上都极 ...

  2. SDWebImage源码解读之SDWebImageDownloaderOperation

    第七篇 前言 本篇文章主要讲解下载操作的相关知识,SDWebImageDownloaderOperation的主要任务是把一张图片从服务器下载到内存中.下载数据并不难,如何对下载这一系列的任务进行设计 ...

  3. SDWebImage源码解读之SDWebImageDownloader

    SDWebImage源码解读之SDWebImageDownloader 第八篇 前言 SDWebImageDownloader这个类非常简单,作者的设计思路也很清晰,但是我想在这说点题外话. 如果有人 ...

  4. SDWebImage源码解读之SDWebImageManager

    第九篇 前言 SDWebImageManager是SDWebImage中最核心的类了,但是源代码确是非常简单的.之所以能做到这一点,都归功于功能的良好分类. 有了SDWebImageManager这个 ...

  5. SDWebImage源码解读之SDWebImagePrefetcher

    > 第十篇 ## 前言 我们先看看`SDWebImage`主文件的组成模块: ![](http://images2015.cnblogs.com/blog/637318/201701/63731 ...

  6. SDWebImage源码解读之分类

    第十一篇 前言 我们知道SDWebImageManager是用来管理图片下载的,但我们平时的开发更多的是使用UIImageView和UIButton这两个控件显示图片. 按照正常的想法,我们只需要在他 ...

  7. SDWebImage源码解读之干货大总结

    这是我认为的一些重要的知识点进行的总结. 1.图片编码简介 大家都知道,数据在网络中是以二进制流的形式传播的,那么我们该如何把那些1和0解析成我们需要的数据格式呢? 说的简单一点就是,当文件都使用二进 ...

  8. SDWebImage源码解读 之 UIImage+GIF

    第二篇 前言 本篇是和GIF相关的一个UIImage的分类.主要提供了三个方法: + (UIImage *)sd_animatedGIFNamed:(NSString *)name ----- 根据名 ...

  9. SDWebImage源码解读 之 SDWebImageCompat

    第三篇 前言 本篇主要解读SDWebImage的配置文件.正如compat的定义,该配置文件主要是兼容Apple的其他设备.也许我们真实的开发平台只有一个,但考虑各个平台的兼容性,对于框架有着很重要的 ...

随机推荐

  1. 1.初始Windows Server 2012 R2 Hyper-V + 系统安装详细

    干啥的?现在企业服务器都是分开的,比如图片服务器,数据库服务器,redis服务器等等,或多或少一个网站都会用到多个服务器,而服务器的成本很高,要是动不动采购几十台,公司绝对吃不消的,于是虚拟化技术出来 ...

  2. HTML 事件(四) 模拟事件操作

    本篇主要介绍HTML DOM中事件的模拟操作. 其他事件文章 1. HTML 事件(一) 事件的介绍 2. HTML 事件(二) 事件的注册与注销 3. HTML 事件(三) 事件流与事件委托 4.  ...

  3. 比Mysqli操作数据库更简便的方式 。PDO

    下面来说一下PDO 先画一张图来了解一下 mysqli是针对mysql这个数据库扩展的一个类 PDO是为了能访问更多数据库 如果出现程序需要访问其他数据库的话就可以用PDO来做 PDO数据访问抽象层1 ...

  4. jQuery动画-圣诞节礼物

    ▓▓▓▓▓▓ 大致介绍 下午看到了一个送圣诞礼物的小动画,正好要快到圣诞节了,就动手模仿并改进了一些小问题 原地址:花式轮播----圣诞礼物传送 思路:动画中一共有五个礼物,他们平均分布在屏幕中,设置 ...

  5. 一篇文章看懂TPCx-BB(大数据基准测试工具)源码

    TPCx-BB是大数据基准测试工具,它通过模拟零售商的30个应用场景,执行30个查询来衡量基于Hadoop的大数据系统的包括硬件和软件的性能.其中一些场景还用到了机器学习算法(聚类.线性回归等).为了 ...

  6. [.NET] 利用 async & await 的异步编程

    利用 async & await 的异步编程 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/5922573.html  目录 异步编程的简介 异 ...

  7. PHP之GD函数的使用

    本文讲解常用GD函数的应用 1.一个简单的图像 我们先看一个例子: <?php $w = 200; $h = 200; $img = imagecreatetruecolor($w,$h); $ ...

  8. linux应用调试技术之GDB和GDBServer

    1.调试原理 GDB调试是应用程序在开发板上运行,然后在PC机上对开发板上得应用程序进行调试,PC机运行GDB,开发板上运行GDBServer.在应用程序调试的时候,pc机上的gdb向开发板上的GDB ...

  9. git图像化界面GUI的使用

    GIT学习笔记 一.        基础内容 1.git是一个版本控制软件,与svn类似,特点是分布式管理,不需要中间总的服务器,可以增加很多分支. 2.windows下的git叫msysgit,下载 ...

  10. ASP.NET Aries JSAPI 文档说明:AR.DataGrid

    AR.DataGrid 文档 用法: <body> <table id="dg"></table> </body> </htm ...