第五篇
前言
本篇主要講解圖片緩存類的知識觉痛,雖然只涉及了圖片方面的緩存的設計,但思想同樣適用于別的方面的設計茵休。在架構上來說薪棒,緩存算是存儲設計的一部分。我們把各種不同的存儲內容按照功能進行切割后榕莺,圖片緩存便是其中的一個俐芯。
我們在封裝自己的圖片緩存管理對象的時候,SDWebImageCache
能夠提供大約90%的代碼給我們直接使用钉鸯,基于這些代碼吧史,我們需要分析出作者的設計思想是什么?當需要緩存某個列表時唠雕,基于SDWebImageCache
的設計思想贸营,我們就能夠設計出比較合理的緩存管理對象了。
所謂舉一反三就是這樣的道理岩睁。
整體架構
我們不看實現文件钞脂,只看作者暴露出來的內容,來分析該類有哪些屬性和方法笙僚》技。看完整體架構
這一節(jié),我們必須明白如何使用這個緩存管理者肋层。具體的實現過程會在下邊的實現原理
一節(jié)中講解亿笤。
1.緩存位置
圖片可以被緩存到兩個地方:
- 內存
- 硬盤
2.配置
通過SDImageCacheConfig
這個類來管理緩存的配置信息,我們打開SDImageCacheConfig
后栋猖,發(fā)現可以配置的東西有:
-
shouldDecompressImages
是否解壓縮圖片净薛,默認為YES -
disable iCloud backup
是否禁用iCloud備份, 默認為YES -
shouldCacheImagesInMemory
是否緩存到內存中蒲拉,默認為YES -
maxCacheAge
最大的緩存不過期時間肃拜, 單位為秒痴腌,默認為一周的時間 -
maxCacheSize
最大的緩存尺寸,單位為字節(jié)
代碼如下:
@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.初始化
一般來說猛蔽,一個管理類都有一個全局的單利對象剥悟,該類也不例外,然后根據業(yè)務需求設計不同的初始化方法曼库。不管是什么樣的類区岗,我們在設計它的時候,應該通過合理的初始化方法告訴別的開發(fā)者毁枯,該類應該如何創(chuàng)建
-
+ (nonnull instancetype)sharedImageCache
單利 -
- (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns
通過制定的namespace
來初始化 -
- (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns diskCacheDirectory:(nonnull NSString *)directory NS_DESIGNATED_INITIALIZER
指定namespace
和path
.
注意:如果想設置某個方法為指定的初始化方法慈缔,通過NS_DESIGNATED_INITIALIZER
來實現。
6.Cache paths
既然把數據緩存到了disk中种玛,那么就要提供一個方法獲取這個緩存路徑藐鹤。這里通過下邊這個方法,根據namespace獲取緩存路徑:
- (nullable NSString *)makeDiskCachePath:(nonnull NSString*)fullNamespace;
注意:在開發(fā)中赂韵,我們會遇到這樣的情況教藻,假如我之前把圖片緩存到了地址1
,現在我打算重構代碼右锨。寫了這么一個緩存管理者括堤,我需要和之前的緩存的圖片建立聯(lián)系,但是以后都打算使用新寫的這個管理者绍移,那怎么辦呢悄窃??
我們想到蹂窖,我只需要把之前的路徑添加到管理類的路徑集合中就行了轧抗。主要目的是在搜索圖片的時候,也有權限去搜索新添加的路徑瞬测。
我在想横媚,一個好的架構,或框架月趟,應該使用這用思想
這也是下邊這個方法的意義:
/**
* 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究竟能夠給我提供哪些功能,更進一步此迅,我們了解到設計這樣一個管理者的答題思路是什么汽畴。下一篇就是該管理者的實現部分。
由于個人知識有限耸序,如有錯誤之處忍些,還望各路大俠給予指出啊