YYCache源码阅读一(YYMemoryCache)
YYCache:高性能 iOS 缓存框架。
YYCache
主要负责管理 YYDiskCache
和 YYMemoryCache
;YYCache
里面每个接口都是由 YYDiskCache
或者是 YYMemoryCache
;来执行的
注意:带有block的方法,并不是在 memory 和 disk 上都会有执行block,只有两个方法,在通过Key获取
value 的时候会在全局队列异步执行block 还有就是在查询是否存在这个key 的时候,会全局队列异步执行
block;
YYMemoryCache
内存缓存
内部实现:
1、有一个inline 函数,返回一个优先级LOW的全局queue;
2、使用双向链表和NSDictionary来实现LRU算法;
3、线程安全由开始OSSpinLock的转为pthread_mutex_lock,因为OSSpinLock已经不再安全了,被Apple废弃了;
4、私有属性:保存数据的_YYLinkedMap *_lru;
保证数据安全的pthread_mutex_t _lock;
串行队列dispatch_queue_t _queue;
LRU算法的实现:_YYLinkedMapNode
和_YYLinkedMap
通过双向链表去操作各个结点
_YYLinkedMapNode: 链表的结点,由于是一个双向的链表(查找会比较快),因此有_prev和_next,另
外添加了key, value ,cost和time
_YYLinkedMap:key_value的链表,包含了链表的_head和_tail,包括了存储数据的CFMutableDictionaryRef类型_dic
这个类里面的方法看名字就知道实现的功能,主要实现了链表结点的插入,移动,删除,具备一定的链表知识就
可以看懂了,这里就不具体去说明实现的细节了;
由于要跟CF里面的对象打交道,需要使用__bridge进行桥接;
具体实现:
init:
对属性的初始化以及添加UIApplicationDidReceiveMemoryWarningNotification和 UIApplicationDidEnterBackgroundNotification的通知后,即开始递归调用方法_trimRecursively,即会默认每5S执行一次方法_trimInBackground;
trimInBackground:
在串行队列_queue中异步执行方法_trimToCost,_trimToCount,_trimToAge;
_trimToCost:
检测costLimit是否超过totalCost,如果超过的话,那就remove,并将remove的object加入到数组
holder中,然后再在主队列或者是全局队列中将数组释放;(这里有一句[holder count],YY给的解释是
holder 持有了待释放的对象,这些对象应该根据配置在不同线程进行释放(release)。此处 holder 被
block 持有,然后在另外的 queue 中释放。[holder count] 只是为了让 holder 被 block 捕获,
保证编译器不会优化掉这个操作,所以随便调用了一个方法。)
注:之后的node也是类似的。
_trimToCount:
同_trimToCost;
_trimToAge:
同_trimToCost;
objectForKey:
通过_dic找到key对应的node,然后重置node->_time为当前时间,并将node设置为_lru的head
setObject:(id)object forKey:(id)key:
调用的是- (void)setObject:(id)object forKey:(id)key withCost:(NSUInteger)cost方法;
如果object为空,则remove key对应的object,如果key为空,则直接返回,否则在_dic中找到这个node,
重新设置node的属性,比如_valye,_time,_cost,并改变_lru的totalCost;然后进行totalCost和
totalCount的检测,如果有超过,就按照设置的去用LRU算法remove相应的node;并在对应线程中释放
node;
这里有个奇怪的地方,就是YY每次给的cost都是0,也就是说,并不会增加,所以设置这个limitcost好像并
没有什么用
其他的基本上跟上面两个的操作差不多,实际上就是对node,linkMap还有CFMutableDictionaryRef的操作;
参考:
YYCache 设计思路: http://blog.ibireme.com/2015/10/26/yycache/
YYCache github地址:https://github.com/ibireme/YYCache
一些注释:
1、__has_include(): 传入的文件名是否可以被引用,如果可以返回1,否则返回0;
2、FOUNDATION_EXPORT: 功能类似于#define 最不过比#define要快一些
3、NS_ASSUME_NONNULL_BEGIN 和 NS_ASSUME_NONNULL_END:在这两个宏定义之间的属性默认都是
NONULL的,除非你自己在重新设置为 nullable
4、%p:输出指针地址
5、__unsafe_unretained: 不会对对象进行retain,当对象销毁时,会依然指向之前的内存空间(野指针)
6、NS_DESIGNATED_INITIALIZER: 指定初始化方法
网友评论