一、概念介绍
SDWebImageCache是SDWebImage中的一个缓存类,是拿来缓存数据的,在SDWebImage中分为缓存数据到磁盘以及内存,下面就简单的介绍下它们头文件的内容,其实它们的头文件的内容就是给我们在外面可以自定义去设置的,可以去调用头文件的方法,本身就是这个框架对外的接口,所以我们应该对其的概念应该有一定的了解
二、代码实战
关于SDImageCache.h文件的内容#import <Foundation/Foundation.h>
#import "SDWebImageCompat.h"
#import "SDImageCacheConfig.h"
//SDImageCacheType主要是拿来做通知的回调,拿到图片的时候,SDWebImage会告诉我们是从磁盘中来还是内存
typedef NS_ENUM(NSInteger, SDImageCacheType) {
/**
* The image wasn't available the SDWebImage caches, but was downloaded from the web.
//没有缓存,图片直接从网络上下载过来
*/
SDImageCacheTypeNone,
/**
* The image was obtained from the disk cache.
图片从磁盘中获取
*/
SDImageCacheTypeDisk,
/**
* The image was obtained from the memory cache.
图片从内存中来
*/
SDImageCacheTypeMemory
};
typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) {
/**
* By default, we do not query disk data when the image is cached in memory. This mask can force to query disk data at the same time.
默认情况下,当图像有缓存到内存中时,我们不会查询磁盘数据。这个选项可以同时强制查询磁盘数据。
*/
SDImageCacheQueryDataWhenInMemory = 1 << 0,
/**
* By default, we query the memory cache synchronously, disk cache asynchronously. This mask can force to query disk cache synchronously.
默认情况下,我们同步查询内存缓存,异步的查询磁盘缓存。此掩码可以同步查询磁盘缓存。
*/
SDImageCacheQueryDiskSync = 1 << 1
};
//查询完毕的block,会把图片和图片的data以及从那边来的回调过去,会传入这个image是从网络上来的,还是磁盘还是内存
typedef void(^SDCacheQueryCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType);
//判断是否有缓存的回调
typedef void(^SDWebImageCheckCacheCompletionBlock)(BOOL isInCache);
//计算文件的大小和文件的数量
typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger totalSize);
/**
* SDImageCache maintains a memory cache and an optional disk cache. Disk cache write operations are performed
* asynchronous so it doesn’t add unnecessary latency to the UI.
*/
@interface SDImageCache : NSObject
#pragma mark - Properties
/**
* Cache Config object - storing all kind of settings
缓存配置对象
*/
@property (nonatomic, nonnull, readonly) SDImageCacheConfig *config;
/**
* The maximum "total cost" of the in-memory image cache. The cost function is the number of pixels held in memory.
//设置缓存中最大的消耗的内存,这里计算的是内存中的像素个数
*/
@property (assign, nonatomic) NSUInteger maxMemoryCost;
/**
* The maximum number of objects the cache should hold.
缓存应该持有的对象的最大数量
*/
@property (assign, nonatomic) NSUInteger maxMemoryCountLimit;
#pragma mark - Singleton and initialization
/**
* Returns global shared cache instance
* 返回全局共享缓存实例
* @return SDImageCache global instance
*/
+ (nonnull instancetype)sharedImageCache;
/**
* Init a new cache store with a specific namespace
* 初始化一个新的缓存命名空间,里面就是去获取磁盘缓存路径,然后再进行一系列的初始化操作
* @param ns The namespace to use for this cache store
*/
- (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns;
/**
* Init a new cache store with a specific namespace and directory
* 用命名空间和路径初始化一个新的缓存路径
* @param ns The namespace to use for this cache store
* @param directory Directory to cache disk images in
*/
- (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns
diskCacheDirectory:(nonnull NSString *)directory NS_DESIGNATED_INITIALIZER;
#pragma mark - Cache paths
//初始化磁盘缓存路径
- (nullable NSString *)makeDiskCachePath:(nonnull NSString*)fullNamespace;
/**
* 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
*添加一个只读缓存路径,由SDImageCache搜索已经预缓存的图像。
如果你想把预装的图片和你的应用捆绑在一起,这很有用。去找图片就也可以在这个路径中进行添加
* @param path The path to use for this read-only cache path
*/
- (void)addReadOnlyCachePath:(nonnull NSString *)path;
#pragma mark - Store Ops
/**
* Asynchronously store an image into memory and disk cache at the given key.
* 根据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.
* 根据toDisk来判断是否要存储到磁盘中,也就是说这里的磁盘缓存是可选的
* @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.
* 这里面的方法会根据imageData如果没有,但是image有的话,就会考虑到图片格式的问题
* @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.
* 根据key保存图片的data,给保存到磁盘缓存中
* @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;
#pragma mark - Query and Retrieve Ops
/**
* Async check if image exists in disk cache already (does not load the image)
* 根据key判断是否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;
/**
* Sync check if image data exists in disk cache already (does not load the image)
* 根据key判断image是否存在磁盘中:同步处理,直接返回结果
* @param key the key describing the url
*/
- (BOOL)diskImageDataExistsWithKey:(nullable NSString *)key;
/**
* Operation that queries the cache asynchronously and call the completion when done.
* 操作以异步方式查询缓存,并在完成时调用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;
/**
* Operation that queries the cache asynchronously and call the completion when done.
* 操作以异步方式查询缓存,并在完成时调用done 这里可以传入options
* @param key The unique key used to store the wanted image
* @param options A mask to specify options to use for this cache query
* @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 options:(SDImageCacheOptions)options done:
(nullable SDCacheQueryCompletedBlock)doneBlock;
/**
* Query the memory cache synchronously.
* 根据key从内存中获取图片
* @param key The unique key used to store the image
*/
- (nullable UIImage *)imageFromMemoryCacheForKey:(nullable NSString *)key;
/**
* Query the disk cache synchronously.
* 据key判断是否Image是否存在磁盘中:同步处理
* @param key The unique key used to store the image
*/
- (nullable UIImage *)imageFromDiskCacheForKey:(nullable NSString *)key;
/**
* Query the cache (memory and or disk) synchronously after checking the memory cache.
*根据key从磁盘缓存或者是内存中获取图片
* @param key The unique key used to store the image
*/
- (nullable UIImage *)imageFromCacheForKey:(nullable NSString *)key;
#pragma mark - Remove Ops
/**
* Remove the image from memory and disk cache asynchronously
* 根据key从内存和磁盘删除缓存图片,异步处理
* @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;
/**
* Remove the image from memory and optionally disk cache asynchronously
* 根据key删除缓存图片,可以指定是否从磁盘删除,回调通知
* @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;
#pragma mark - Cache clean Ops
/**
* Clear all memory cached images
清空内存缓存图片
*/
- (void)clearMemory;
/**
* 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;
#pragma mark - Cache Info
/**
* Get the size used by the disk cache
同步操作:获取缓存中所有文件的大小
*/
- (NSUInteger)getSize;
/**
* Get the number of images in the disk cache
同步操作:获取磁盘缓存中图片数
*/
- (NSUInteger)getDiskCount;
/**
异步操作:获取缓存中图片数及图片所占内存总大小
* Asynchronously calculate the disk cache's size.
*/
- (void)calculateSizeWithCompletionBlock:(nullable SDWebImageCalculateSizeBlock)completionBlock;
#pragma mark - Cache Paths
/**
* Get the cache path for a certain key (needs the cache path root folder)
* 需要根路径和key来查询文件所在的位置
* @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
* 根据key获取相应文件的默认的缓存路径
* @param key the key (can be obtained from url using cacheKeyForURL)
*
* @return the default cache path
*/
- (nullable NSString *)defaultCachePathForKey:(nullable NSString *)key;
@end
关于SDImageCacheConfig.h文件的内容,关于这个缓存配置的对象,也是暴露在SDWebImageCache.h文件中的一个属性,所以其实我们自己也可以对其进行定制修改
#import <Foundation/Foundation.h>
#import "SDWebImageCompat.h"
@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.
默认为YES。如果由于内存消耗过大而导致崩溃,请将此设置为NO。
*/
@property (assign, nonatomic) BOOL shouldDecompressImages;
/**
* disable iCloud backup [defaults to YES]
//是否禁止iCloud备份,默认为YES,沙盒中的Documents会备份以及Library/Preference里面的文件
*/
@property (assign, nonatomic) BOOL shouldDisableiCloud;
/**
* use memory cache [defaults to YES]
是否启用内存缓存,默认为YES
*/
@property (assign, nonatomic) BOOL shouldCacheImagesInMemory;
/**
* The reading options while reading cache from disk.
* Defaults to 0. You can set this to `NSDataReadingMappedIfSafe` to improve performance.
*/
@property (assign, nonatomic) NSDataReadingOptions diskCacheReadingOptions;
/**
* The writing options while writing cache to disk.
* Defaults to `NSDataWritingAtomic`. You can set this to `NSDataWritingWithoutOverwriting` to prevent overwriting an existing file.
*/
@property (assign, nonatomic) NSDataWritingOptions diskCacheWritingOptions;
/**
* 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.
磁盘缓存的最大大小 默认为0表示不做限制
*/
@property (assign, nonatomic) NSUInteger maxCacheSize;
@end
下面是SDImageCacheConfig..m文件中的缓存配置中默认的初始化方法其实就一个方法,下面也写了默认的缓存时间为一周
#import "SDImageCacheConfig.h"
static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week
@implementation SDImageCacheConfig
- (instancetype)init {
if (self = [super init]) {
_shouldDecompressImages = YES;
_shouldDisableiCloud = YES;
_shouldCacheImagesInMemory = YES;
_diskCacheReadingOptions = 0;
_diskCacheWritingOptions = NSDataWritingAtomic;
_maxCacheAge = kDefaultCacheMaxCacheAge;
_maxCacheSize = 0;
}
return self;
}
@end
这里面使用的SDWebImageCache类,这个类继承自NSCache,这里就简单的说下其的用法,这个类有两个属性,其中weakCache相当于就是一个二级弱缓存,而weakCacheLock就是一个保证操作二级弱缓存线程安全。
@property (nonatomic, strong, nonnull) NSMapTable<KeyType, ObjectType> *weakCache; // strong-weak cache
@property (nonatomic, strong, nonnull) dispatch_semaphore_t weakCacheLock; // a lock to keep the access to `weakCache` thread-safe
在init方法中创建二级缓存,并且注册收到内存缓存的通知,使用二级缓存的好处其实就是在收到内存警告的时候,当cache被清空的时候,但是图片的实例还可能在imageView中,所以这个时候我们有二级缓存之后,我们可以不用再去磁盘去加载,而是直接从这个缓存中加载
- (instancetype)init {
self = [super init];
if (self) {
// Use a strong-weak maptable storing the secondary cache. Follow the doc that NSCache does not copy keys
/* This is useful when the memory warning, the cache was purged. However, the image instance can be retained by other
instance such as imageViews and alive.*/
// At this case, we can sync weak cache back and do not need to load from disk cache
//NSPointerFunctionsStrongMemory强引用key,弱引用value
self.weakCache = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsWeakMemory capacity:0];
self.weakCacheLock = dispatch_semaphore_create(1);
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(didReceiveMemoryWarning:)
name:UIApplicationDidReceiveMemoryWarningNotification
object:nil];
}
return self;
}
收到内存警告的时候,调用super的removeAllObjects方法,清除图片缓存
- (void)didReceiveMemoryWarning:(NSNotification *)notification {
// Only remove cache, but keep weak cache
[super removeAllObjects];
}
在这个类当中还用到了两个宏,其实就是用GCD的信号量来控制执行的线程的并发数
#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
#define UNLOCK(lock) dispatch_semaphore_signal(lock);