美文网首页
YYCache源码阅读一YYMemoryCache

YYCache源码阅读一YYMemoryCache

作者: AppleTTT | 来源:发表于2017-04-26 18:08 被阅读174次

    YYCache源码阅读一(YYMemoryCache)

    YYCache:高性能 iOS 缓存框架。

    YYCache 主要负责管理 YYDiskCacheYYMemoryCacheYYCache 里面每个接口都是由 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: 指定初始化方法
    
    相关阅读
    1. YYCache源码阅读一YYYDiskCache
    2. YYCache源码阅读一YYStorage

    相关文章

      网友评论

          本文标题:YYCache源码阅读一YYMemoryCache

          本文链接:https://www.haomeiwen.com/subject/cukwzttx.html