NSCache&YYCache

1,459 阅读2分钟

NSCache

  • NSCache是系统提供的一种类似于集合(NSMutableDictionary)的缓存,它与集合的不同如下:

      1. NSCache具有自动删除的功能,以减少系统占用的内存;
      1. NSCache是线程安全的,不需要加线程锁;
      1. 键对象不会像 NSMutableDictionary 中那样被复制。(键不需要实现 NSCopying 协议)。
  • NSCache的属性以及方法介绍:

    • @property NSUInteger totalCostLimit;

      • 设置缓存占用的内存大小,并不是一个严格的限制,当总数超过了totalCostLimit设定的值,系统会清除一部分缓存,直至总消耗低于totalCostLimit的值。
    • @property NSUInteger countLimit;

      • 设置缓存对象的大小,这也不是一个严格的限制。
    • (id)objectForKey:(id)key;

      • 获取缓存对象,基于key-value对
    • (void)setObject:(id)obj forKey:(id)key; // 0 cost

      • 存储缓存对象,考虑缓存的限制属性;
    • (void)setObject:(id)obj forKey:(id)key cost:(NSUInteger)g;

      • 存储缓存对象,cost是提前知道该缓存对象占用的字节数,也会考虑缓存的限制属性,建议直接使用  - (void)setObject:(id)obj forKey:(id)key;
  • NSCacheDelegate代理 代理属性声明如下:

  • @property (assign) iddelegate;

    • 实现了NSCacheDelegate代理的对象,在缓存对象即将被清理的时候,系统回调代理方法如下:
    • (void)cache:(NSCache *)cache willEvictObject:(id)obj;

      • 第一个参数是当前缓存(NSCache),不要修改该对象;

      • 第二个参数是当前将要被清理的对象,如果需要存储该对象,可以在此操作(存入Sqlite or CoreData);

  • 该代理方法的调用会在缓存对象即将被清理的时候调用,如下场景会调用:

        • (void)removeObjectForKey:(id)key; 手动删除对象;
      1. 缓存对象超过了NSCache的属性限制;(countLimit 和 totalCostLimit )
      1. App进入后台会调用;
      1. 系统发出内存警告;
  • 练习

#import "ViewController.h"

@interface ViewController ()<NSCacheDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    NSCache *cache = [[NSCache alloc]init];
    cache.name = @"testCache";
    [cache setCountLimit:5];
    cache.delegate = self;
    NSString *test = @"Hello NSCache";
    [cache setObject:test forKey:@"Test"];
    
    NSLog(@"objectForKey:%@",[cache objectForKey:@"Test"]);
    NSLog(@"name:%@",cache.name);
    for (int i = 0; i < 10; i++)
    {
        [cache setObject:[NSString stringWithFormat:@"WorldCost%d", i] forKey:[NSString stringWithFormat:@"HelloCost%d", i] cost:1];
        NSLog(@"Add key:%@  value:%@ to Cache", [NSString stringWithFormat:@"HelloCost%d", i], [NSString stringWithFormat:@"WorldCost%d", i]);
    }
//    for (int i = 0; i < 10; i++)
//    {
//        [cache setObject:[NSString stringWithFormat:@"World%d", i] forKey:[NSString stringWithFormat:@"Hello%d", i]];
//        NSLog(@"Add key:%@  value:%@ to Cache", [NSString stringWithFormat:@"Hello%d", i], [NSString stringWithFormat:@"World%d", i]);
//    }
//    for (int i = 0; i < 10; i++)
//    {
//        NSLog(@"Get value:%@ for key :%@", [cache objectForKey:[NSString stringWithFormat:@"Hello%d", i]], [NSString stringWithFormat:@"Hello%d", i]);
//    }
////    [cache removeAllObjects];
//    for (int i = 0; i < 10; i++)
//    {
//        NSLog(@"Get value:%@ for key:%@", [cache objectForKey:[NSString stringWithFormat:@"World%d", i]], [NSString stringWithFormat:@"World%d", i]);
//    }
//    NSLog(@"Test %@", test);
//
}
// 当缓存中的一个对象即将被删除时会回调此方法
- (void)cache:(NSCache *)cache willEvictObject:(nonnull id)obj
{
    NSLog(@"Remove Object %@", obj);
}

@end

YYCache的基础使用

- (void)YYCacheSyncTest{
    //模拟数据
    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];
}
- (void)YYCacheAsyncTest{
    //模拟数据
    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");
        }
    }];
}
- (void)YYCacheLurTest{
    YYCache *yyCache=[YYCache cacheWithName:@"LCJCache1"];
    [yyCache.memoryCache setCountLimit:10];//内存最大缓存数据个数
    [yyCache.memoryCache setCostLimit:1*1024];//内存最大缓存开销 目前这个毫无用处
    [yyCache.diskCache setCostLimit:10*1024];//磁盘最大缓存开销
    [yyCache.diskCache setCountLimit:10];//磁盘最大缓存数据个数
    [yyCache.diskCache setAutoTrimInterval:1];//设置磁盘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)(2 * 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:@"key%d",i];
             id vuale=[yyCache objectForKey:key];
             NSLog(@"key :%@ value : %@",key ,vuale);
         }

     });
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self YYCacheLurTest];
}