YYCache源码学习总结

      YYCache,具体使用就不做介绍了,是由简书的ibireme大神开发的三方缓存框架。最近项目中遇到了缓存问题,借此机会读了一下YYCache的源码,写的非常清晰,对作者也是由衷的膜拜。

      我也总结了一下YYCache,它的结构两方面,一是内存缓存,二是磁盘缓存。内存缓存上线程安全使用的pthread_mutex_lock(),通过作者的简书的描述,看出作者曾经线程安全上使用的OSSpinLock,但是由于OSSpinLock在新版的ios中已经不能保证线程安全了,所以作者将OSSpinLock替换为了现在的pthread_mutex_lock()来保证线程安全。

      我认为项目中一旦使用三方框架,就应该去明白框架内部结构与实现原理,一呢是方便后期维护,二呢对自己来说也是种学习。所以在读YYCache源码的时候我带着下面几个问题去读。

      对于内存缓存上,一是内存缓存是怎么实现的,二是内存缓存是如何通过内存容量和缓存数量进行清理的,因为在此之前,项目中曾经使用过了大名顶顶的SDWebImage框架做过图片处理,对于内存释放上,一旦内存容积达到上限或者存储数量达到上限就会以通知的方式进行缓存处理。所以既然学习缓存,就要了解它的缓存机制与释放机制。它的缓存内部用双向链表和 NSDictionary 实现了 LRU 淘汰算法,如果当前节点存在,说明缓存已存在,更新缓存大小/缓存时间/缓存内容,并把当前节点设置为头节点。如果当前节点不存在,新建节点,设置缓存大小/缓存时间/缓存内容,插入该节点为头节点。缓存释放上,对外分别提供了时间/数量/容量的接口,实际内部仍然是对链表的操作。有一点需要注意的是它会优先移除掉尾节点,当然新插入和最近使用到的也会插入都头节点。

      对于磁盘缓存上,同样还是上面的两个问题。磁盘缓存上,它是通过文件加数据库的方式进行存取。实际文件的操作在YYKVStorage类中。以下注释为它的缓存策略:

 *         filename     != null
 *                          则用文件缓存value,并把`key`,`filename`,`extendedData`写入数据库
 *         filename     == null
 *                          缓存方式type:YYKVStorageTypeFile 不进行缓存
 *                          缓存方式type:YYKVStorageTypeSQLite||YYKVStorageTypeMixed 数据库缓存

通过源码我们可以看出,filename生成的条件需要存储的文件长度大与_inlineThreshold,源码中_inlineThreshold被设置为20kb,也就是说文件大小如果大于20kb,那么就会通过key给此文件生成filename,通过源码,一旦有filename,value就不会被数据库存储,而是写进文件中,如果没有filename,数据库就会对value进行存储,这也算是作者对数据库和文件读写的充分利用其高性能吧。

    if (fileName.length == 0) {
        sqlite3_bind_blob(stmt, 4, value.bytes, (int)value.length, 0);
    } else {
        sqlite3_bind_blob(stmt, 4, NULL, 0, 0);
    }

      还有一个问题需要明白,就是磁盘存储我们存在了什么位置?我们看下源代码。YYCache类中的- (instancetype)initWithName:(NSString *)name方法,我们最后能够找到YYKVStorage中的- (instancetype)initWithPath:(NSString *)path type:(YYKVStorageType)type方法,里面有几个路径我们需要了解下。还是看下源代码:

//文件存储路径  
_dataPath = [path stringByAppendingPathComponent:kDataDirectoryName];
//数据库打开失败或者异常垃圾文件回收路径
_trashPath = [path stringByAppendingPathComponent:kTrashDirectoryName];
//数据库存储路径
_dbPath = [path stringByAppendingPathComponent:kDBFileName];

      关于缓存清理机制,和内存缓存相似,也是通过缓存大小/缓存数量/缓存时间进行清理。还是看下源码:

/**
 *  删除所有内存开销大于size的缓存
 */
- (BOOL)removeItemsLargerThanSize:(int)size;
/**
 *  删除所有时间比time小的缓存(缓存按时间清理)
 */
- (BOOL)removeItemsEarlierThanTime:(int)time;
/**
 *  减小缓存占的容量开销,使总缓存的容量开销值不大于maxSize(删除原则:LRU 最久未使用的缓存将先删除)
 */
- (BOOL)removeItemsToFitSize:(int)maxSize;

/**
 *  减小总缓存数量,使总缓存数量不大于maxCount(删除原则:LRU 最久未使用的缓存将先删除)
 */
- (BOOL)removeItemsToFitCount:(int)maxCount;
/**
 *  清空所有缓存
 */
- (BOOL)removeAllItems;
- (void)removeAllItemsWithProgressBlock:(nullable void(^)(int removedCount, int totalCount))progress
                               endBlock:(nullable void(^)(BOOL error))end;

      最后再说一点:通过源码我们能够看到,我们存储和取出的对象都为id类型并且实现了NSCoding协议,那么实际上它是以什么类型存储的呢,通过

value = [NSKeyedArchiver archivedDataWithRootObject:object]可以看出是通过归档的方式将其归档为NSData类型进行存储,同理我们在读取缓存的时候

object = [NSKeyedUnarchiver unarchiveObjectWithData:item.value]将其反序列化拿到id类型的object对象进行使用。

转载于:https://www.cnblogs.com/byxixiblogs/p/6773035.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值