SDWebImage学习笔记之SDImageCache
SDMemoryCache
SDMemoryCache是SDImageCache类中的一个私有类,继承自NSCache类,它接收两个泛型<KeyType, ObjectType>使用于定义NSMapTable类型的属性weakCache。
// strong-weak cache@property (nonatomic, strong, nonnull) NSMapTable<KeyType, ObjectType> *weakCache;
NSMapTable在SDWebImage学习笔记之NSMapTable中做过详情,weakCache属性的初始化代码为
self.weakCache = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsWeakMemory capacity:0];
表示weakCache变量指向的对象强引使用key值,弱引使用value值。如果没有其余变量强引使用value值,weakCache变量将安全的删除相应的key-value。
SDMemoryCache还定义了一个dispatch_semaphore_t属性weakCacheLock。
// a lock to keep the access to `weakCache` thread-safe@property (nonatomic, strong, nonnull) dispatch_semaphore_t weakCacheLock;
weakCacheLock属性创立了一个初始值为1的信号量,表示同时最多只有一个线程可以访问资源,初始化代码为:
self.weakCacheLock = dispatch_semaphore_create(1);
SDMemoryCache重写了父类NSCache的三个方法:
- -(nullable ObjectType)objectForKey:(KeyType)key;
- -(void)setObject:(ObjectType)obj forKey:(KeyType)key cost:(NSUInteger)g;
- -(void)removeObjectForKey:(KeyType)key;
通过对信号量weakCacheLock的控制,实现线程安全的weakCache赋值、取值、删除操作,还提供了一个清空缓存的函数
-(void)removeAllObjects。
#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);#define UNLOCK(lock) dispatch_semaphore_signal(lock);FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) {#if SD_MAC return image.size.height * image.size.width;#elif SD_UIKIT || SD_WATCH return image.size.height * image.size.width * image.scale * image.scale;#endif// Store weak cacheLOCK(self.weakCacheLock);[self.weakCache setObject:obj forKey:key];UNLOCK(self.weakCacheLock);// Check weak cacheLOCK(self.weakCacheLock);obj = [self.weakCache objectForKey:key];UNLOCK(self.weakCacheLock);if (obj) { // Sync cache NSUInteger cost = 0; if ([obj isKindOfClass:[UIImage class]]) { cost = SDCacheCostForImage(obj); } [super setObject:obj forKey:key cost:cost];}// Remove weak cacheLOCK(self.weakCacheLock);[self.weakCache removeObjectForKey:key];UNLOCK(self.weakCacheLock);// Manually remove should also remove weak cacheLOCK(self.weakCacheLock);[self.weakCache removeAllObjects];UNLOCK(self.weakCacheLock);
SDMemoryCache小结
SDMemoryCache类的两个属性:weakCache和weakCacheLock。weakCache使用于保存数据,且当数据在外部被销毁时,weakCache可以安全的清理对应的键值对;weakCacheLock使用于保证线程安全,同一时刻只允许只允许有一个线程对weakCache进行读写。
SDImageCacheConfig
SDImageCacheConfig使用于SDImageCache的配置,继承自NSObject,定义配置属性如下:
// 能否解压图片@property (assign, nonatomic) BOOL shouldDecompressImages;// 能否禁使用iCloud@property (assign, nonatomic) BOOL shouldDisableiCloud;// 能否用内存缓存,默认YES@property (assign, nonatomic) BOOL shouldCacheImagesInMemory;// 磁盘缓存读取选项,枚举@property (assign, nonatomic) NSDataReadingOptions diskCacheReadingOptions;// 磁盘缓存写当选项,枚举@property (assign, nonatomic) NSDataWritingOptions diskCacheWritingOptions;// 在缓存中保存图像的最长时间,以秒为单位@property (assign, nonatomic) NSInteger maxCacheAge;// 缓存的最大大小,以字节为单位@property (assign, nonatomic) NSUInteger maxCacheSize;// 缓存配置过期类型,枚举@property (assign, nonatomic) SDImageCacheConfigExpireType diskCacheExpireType;
SDImageCache
SDImageCache是Cache板块的核心类,它提供了一系列的方法来存储图片,以其中最重要的存储方法为例:
- (void)storeImage:(nullable UIImage *)image imageData:(nullable NSData *)imageData forKey:(nullable NSString *)key toDisk:(BOOL)toDisk completion:(nullable SDWebImageNoParamsBlock)completionBlock;
该方法共有6个参数,image表示图片,imageData表示图片数据,在赋值时,代码先判断imageData能否为空,不为空则直接将NSData类型的数据进行存储,假如imageData为空且image不为空,则先判断UIImage类型的图片能否存在Alpha(透明)通道,返回一个SDImageFormat类型的枚举值使用于将UIImage转化为NSData,而后进行存储。
// 及时释放图片资源@autoreleasepool { NSData *data = imageData; // 判断imageData能否为空 if (!data && image) { // 判断images能否存在Alpha Channel SDImageFormat format; if (SDCGImageRefContainsAlpha(image.CGImage)) { format = SDImageFormatPNG; } else { format = SDImageFormatJPEG; } // UIImage -> NSData data = [[SDWebImageCodersManager sharedInstance] encodedDataWithImage:image format:format]; } // 存储data [self _storeImageDataToDisk:data forKey:key];}
第三个参数key有两个作使用,一是在内存缓存可使用的前提下作为key存储图片,形成映射关系;二是生成磁盘缓存的URL地址,将图片保存在该地址下,后期可以通过key获取地址。
1.// 内存缓存可使用if (self.config.shouldCacheImagesInMemory) { // 计算图片占使用空间大小 NSUInteger cost = SDCacheCostForImage(image); // 将key和image作为键值对存储在NSMapTable类型的内存缓存中 [self.memCache setObject:image forKey:key cost:cost];}2.// _storeImageDataToDisk:forkey:方法// 用key生成磁盘缓存地址NSString *cachePathForKey = [self defaultCachePathForKey:key];// 将地址转换成NSURL对象NSURL *fileURL = [NSURL fileURLWithPath:cachePathForKey];// 存储图片[imageData writeToURL:fileURL options:self.config.diskCacheWritingOptions error:nil];
第四个参数toDisk使用于标示能否需要将图片存储到磁盘,需要的话才会执行存储的操作,第五个参数completionBlock是执行结束的回调,返回值为空。
if (toDisk) { // 开启新的线程执行 dispatch_async(self.ioQueue, ^{ // 将图片缓存到磁盘 ...... if (completionBlock) { // 返回主线程执行 dispatch_async(dispatch_get_main_queue(), ^{ completionBlock(); }); } });} else { if (completionBlock) { completionBlock(); }}
SDImageCache类中定义了属性ioQueue,它创立了一个串行队列。
_ioQueue = dispatch_queue_create("com.hackemist.SDWebImageCache", DISPATCH_QUEUE_SERIAL);
串行队列在执行异步操作时,会开启一个新的线程来执行,具体可参考下表:
同步 | 异步 | |
---|---|---|
串行队列(主队列) | 在主线程中执行 | 在主线程中执行 |
串行队列(非主队列) | 在当前线程中执行 | 在新建线程中执行 |
并发队列 | 在当前线程中执行 | 在新建线程中执行 |
因而在子线程完成存储图片的操作后,需返回到主线程队列执行回调函数。
SDImageCache还提供了查询图片能否存在于磁盘、获取磁盘图片、查询内存图片、删除磁盘图片、删除内存图片等方法,同样,所有的方法都会在串行队列中异步执行,因为串行队列遵守FIFO(先进先出)的准则,所以可以保证只有才一个操作完成后,下一个方法才可以被执行。
当从硬盘中获取图片时,代码会判断内存缓存能否可使用,假如可使用,则将图片缓存到内存中。
// 获取图片- (nullable UIImage *)imageFromDiskCacheForKey:(nullable NSString *)key { UIImage *diskImage = [self diskImageForKey:key]; // 判断图片能否存在及内存缓存能否可使用 if (diskImage && self.config.shouldCacheImagesInMemory) { NSUInteger cost = SDCacheCostForImage(diskImage); [self.memCache setObject:diskImage forKey:key cost:cost]; } return diskImage;}
SDImageCache中定义了一个属性customPaths,可以调使用addReadOnlyCachePath:方法往customPaths数组中增加常使用的磁盘缓存路径,以便diskImageDataBySearchingAllPathsForKey:方法查找图片资源。
- (nullable NSData *)diskImageDataBySearchingAllPathsForKey:(nullable NSString *)key { ...... NSArray<NSString *> *customPaths = [self.customPaths copy]; for (NSString *path in customPaths) { ...... } ......}
除了对图片的操作之外,SDImageCache还提供了内存缓存的设置功能,包括设置缓存大小和数量限制,还提供了清除内存缓存、清除磁盘缓存、删除文件的方法,还有少量其余获取图片信息、缓存信息的方法等等。
总结
SDImageCache的核心功能是对图片的存储、查找、删除操作。提供了两种方法使用于缓存图片,内存缓存和磁盘缓存。
内存指的是程序的运行空间,空间小但缓存速度快,程序一关闭,内存就被释放了,内存分5大区域:栈区、堆区、全局区、常量区、代码区,由高地址指向低地址。
磁盘指的是程序的存储空间,空间大但缓存速度慢,数据可持久化。
iOS程序的磁盘被称为沙盒,本程序无法访问其余应使用的沙盒,沙盒中默认有3个文件夹:Documents, Library 和 tmp。
而且所有的操作都是在串行队列中异步执行,即不会阻塞主线程,也保证了数据的安全性。
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » SDWebImage学习笔记之SDImageCache