• 使用YYCache开源框架实现缓存IOS缓存管理
  • 小白狼 发表于 2017/2/24 11:25:00 | 分类标签: IOS缓存管理 YYCache框架
  • 关于YYCache

    1. 内存缓存(YYMemoryCache)

    存储的单元是_YYLinkedMapNode,除了key和value外,还存储了它的前后Node的地址_prev,_next.整个实现基于_YYLinkedMap,它是一个双向链表,除了存储了字典_dic外,还存储了头结点和尾节点.它实现的功能很简单,就是:有新数据了插入链表头部,访问过的数据结点移到头部,内存紧张时把尾部的结点移除.就这样实现了淘汰算法.因为内存访问速度很快,锁占用的时间少,所以用的速度最快的OSSpinLockLock

    2. 硬盘缓存(YYDiskCache)

    采用的是文件和数据库相互配合的方式.有一个参数inlineThreshold,默认20KB,小于它存数据库,大于它存文件.能获得效率的提高.key:path,value:cache存储在NSMapTable里.根据path获得cache,进行一系列的set,get,remove操作更底层的是YYKVStorage,它能直接对sqlite和文件系统进行读写.每次内存超过限制时,select key, filename, size from manifest order by last_access_time desc limit ?1会根据时间排序来删除最近不常用的数据.硬盘访问的时间比较长,如果用OSSpinLockLock锁会造成CPU消耗过大,所以用的dispatch_semaphore_wait来做.

    YYCache使用

    1.同步方式

        //模拟数据
        NSString *value=@"I want to know who is lcj ?";
        //模拟一个key
        //同步方式
        NSString *key=@"key";
        YYCache *yyCache=[YYCache cacheWithName:@"LCJCache"];
        //根据key写入缓存value
        [yyCache setObject:value forKey:key];
        //判断缓存是否存在
        BOOL isContains=[yyCache containsObjectForKey:key];
        NSLog(@"containsObject : %@", isContains?@"YES":@"NO");
        //根据key读取数据
        id vuale=[yyCache objectForKey:key];
        NSLog(@"value : %@",vuale);
        //根据key移除缓存
        [yyCache removeObjectForKey:key];
        //移除所有缓存
        [yyCache removeAllObjects];

    2.异步方式

        //模拟数据
        NSString *value=@"I want to know who is lcj ?";
        //模拟一个key
        //异步方式
        NSString *key=@"key";
        YYCache *yyCache=[YYCache cacheWithName:@"LCJCache"];
        //根据key写入缓存value
        [yyCache setObject:value forKey:key withBlock:^{
            NSLog(@"setObject sucess");
        }];
        //判断缓存是否存在
        [yyCache containsObjectForKey:key withBlock:^(NSString * _Nonnull key, BOOL contains) {
            NSLog(@"containsObject : %@", contains?@"YES":@"NO");
        }];
    
        //根据key读取数据
        [yyCache objectForKey:key withBlock:^(NSString * _Nonnull key, id<NSCoding>  _Nonnull object) {
            NSLog(@"objectForKey : %@",object);
        }];
    
        //根据key移除缓存
        [yyCache removeObjectForKey:key withBlock:^(NSString * _Nonnull key) {
            NSLog(@"removeObjectForKey %@",key);
        }];
        //移除所有缓存
        [yyCache removeAllObjectsWithBlock:^{
            NSLog(@"removeAllObjects sucess");
        }];
    
        //移除所有缓存带进度
        [yyCache removeAllObjectsWithProgressBlock:^(int removedCount, int totalCount) {
            NSLog(@"removeAllObjects removedCount :%d  totalCount : %d",removedCount,totalCount);
        } endBlock:^(BOOL error) {
            if(!error){
                NSLog(@"removeAllObjects sucess");
            }else{
                NSLog(@"removeAllObjects error");
            }
        }];
    YYCache缓存LRU清理

      LRU(Least Recently Used)算法大家都比较熟悉,翻译过来就是“最近最少使用”,LRU缓存就是使用这种原理实现,简单的说就是缓存一定量的数据,当超过设定的阈值时就把一些过期的数据删除掉,比如我们缓存10000条数据,当数据小于10000时可以随意添加,当超过10000时就需要把新的数据添加进来,同时要把过期数据删除,以确保我们最大缓存10000条,那怎么确定删除哪条过期数据呢,采用LRU算法实现的话就是将最老的数据删掉。接下来我们测试一下
        YYCache *yyCache=[YYCache cacheWithName:@"LCJCache"];
        [yyCache.memoryCache setCountLimit:50];//内存最大缓存数据个数
        [yyCache.memoryCache setCostLimit:1*1024];//内存最大缓存开销 目前这个毫无用处
        [yyCache.diskCache setCostLimit:10*1024];//磁盘最大缓存开销
        [yyCache.diskCache setCountLimit:50];//磁盘最大缓存数据个数
        [yyCache.diskCache setAutoTrimInterval:60];//设置磁盘lru动态清理频率 默认 60秒

    模拟一下清理

       for(int i=0 ;i<100;i++){
            //模拟数据
            NSString *value=@"I want to know who is lcj ?";
            //模拟一个key
            NSString *key=[NSString stringWithFormat:@"key%d",i];
            [yyCache setObject:value forKey:key];
        }
    
        NSLog(@"yyCache.memoryCache.totalCost:%lu",(unsigned long)yyCache.memoryCache.totalCost);
        NSLog(@"yyCache.memoryCache.costLimit:%lu",(unsigned long)yyCache.memoryCache.costLimit);
    
        NSLog(@"yyCache.memoryCache.totalCount:%lu",(unsigned long)yyCache.memoryCache.totalCount);
        NSLog(@"yyCache.memoryCache.countLimit:%lu",(unsigned long)yyCache.memoryCache.countLimit);
    
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(120 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    
            NSLog(@"yyCache.diskCache.totalCost:%lu",(unsigned long)yyCache.diskCache.totalCost);
            NSLog(@"yyCache.diskCache.costLimit:%lu",(unsigned long)yyCache.diskCache.costLimit);
    
            NSLog(@"yyCache.diskCache.totalCount:%lu",(unsigned long)yyCache.diskCache.totalCount);
            NSLog(@"yyCache.diskCache.countLimit:%lu",(unsigned long)yyCache.diskCache.countLimit);
    
            for(int i=0 ;i<100;i++){
                //模拟一个key
                NSString *key=[NSString stringWithFormat:@"whoislcj%d",i];
                id vuale=[yyCache objectForKey:key];
                NSLog(@"key :%@ value : %@",key ,vuale);
            }
    
        });
      YYCache和PINCache一样并没有实现基于最大内存开销进行LRU,不过YYCache实现了最大缓存数据个数进行LRU清理,这一点也是选择YYCache原因之一,对于YYCache磁盘LRU清理并不是及时清理,而是后台开启一个定时任务进行RLU清理操作,定时时间默认是60s。

    YYCache与PINCache对比

     对于我这里的使用场景大部分用于缓存json字符串,我这里就以存储字符串来对比一下写入与读取效率

    1.写入性能对比

    YYCache


        //模拟数据
        NSString *value=@"I want to know who is lcj ?";
        //模拟一个key
        NSString *key=@"key";
        //YYCache
        YYCache *yyCache=[YYCache cacheWithName:@"LCJCache"];
        //写入数据
        CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
        [yyCache setObject:value forKey:key withBlock:^{
            CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();
    
            NSLog(@" yyCache async setObject time cost: %0.5f", end - start);
        }];
    
        CFAbsoluteTime start1 = CFAbsoluteTimeGetCurrent();
        [yyCache setObject:value forKey:key];
        CFAbsoluteTime end1 = CFAbsoluteTimeGetCurrent();
        NSLog(@" yyCache sync setObject time cost: %0.5f", end1 - start1);

    运行结果

    PINCache


         //PINCache
        //模拟数据
        NSString *value=@"I want to know who is lcj ?";
        //模拟一个key
        NSString *key=@"key";
        PINCache *pinCache=[PINCache sharedCache];
        //写入数据
        CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
        [pinCache setObject:value forKey:key block:^(PINCache * _Nonnull cache, NSString * _Nonnull key, id  _Nullable object) {
            CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();
            
            NSLog(@" pincache async setObject time cost: %0.5f", end - start);
        }];
        
        CFAbsoluteTime start1 = CFAbsoluteTimeGetCurrent();
        [pinCache setObject:value forKey:key];
        CFAbsoluteTime end1 = CFAbsoluteTimeGetCurrent();
        NSLog(@" pinCache sync setObject time cost: %0.5f", end1 - start1);

    运行结果

    通过上面的测试可以看出 同样大小的数据,无论同步方式还是异步方式,YYCache性能都要由于PINCache。

    2.读取性能对比

    YYCache

        YYCache *yyCache=[YYCache cacheWithName:@"LCJCache"];
        //模拟一个key
        NSString *key=@"key";
        CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
        //读取数据
        [yyCache objectForKey:key withBlock:^(NSString * _Nonnull key, id<NSCoding>  _Nonnull object) {
            CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();
            NSLog(@" yyCache async objectForKey time cost: %0.5f", end - start);
        }];
    
        CFAbsoluteTime start1 = CFAbsoluteTimeGetCurrent();
        [yyCache objectForKey:key];
        CFAbsoluteTime  end1 = CFAbsoluteTimeGetCurrent();
        NSLog(@" yyCache sync objectForKey time cost: %0.5f", end1 - start1);

    运行结果:

    PINCache

      PINCache *pinCache=[PINCache sharedCache];
        //模拟一个key
        NSString *key=@"key";
        CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
        //读取数据
        [pinCache objectForKey:key block:^(PINCache * _Nonnull cache, NSString * _Nonnull key, id  _Nullable object) {
            CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();
            NSLog(@" pincache async objectForKey time cost: %0.5f", end - start);
        }] ;
        
        CFAbsoluteTime start1 = CFAbsoluteTimeGetCurrent();
        [pinCache objectForKey:key];
        CFAbsoluteTime end1 = CFAbsoluteTimeGetCurrent();
        NSLog(@" pinCache objectForKey time cost: %0.5f", end1 - start1);

    运行结果:

    通过运行结果,在读取方面YYCache也是优于PINCache。

    总结:

    经过一番查阅资料和自己写例子测试,最终项目中决定使用YYCache进行缓存管理
  • 请您注意

    ·自觉遵守:爱国、守法、自律、真实、文明的原则

    ·尊重网上道德,遵守《全国人大常委会关于维护互联网安全的决定》及中华人民共和国其他各项有关法律法规

    ·严禁发表危害国家安全,破坏民族团结、国家宗教政策和社会稳定,含侮辱、诽谤、教唆、淫秽等内容的作品

    ·承担一切因您的行为而直接或间接导致的民事或刑事法律责任

    ·您在编程中国社区新闻评论发表的作品,本网站有权在网站内保留、转载、引用或者删除

    ·参与本评论即表明您已经阅读并接受上述条款

  • 感谢本文作者
  • 作者头像
  • 昵称:小白狼
  • 加入时间:2013/6/5 0:00:00
  • TA的签名
  • 这家伙很懒,虾米都没写
  • +进入TA的空间
  • 以下内容也很赞哦
分享按钮