缓存组件中的NSCache

背景

缓存是App中必不可少的机制之一,它能大幅提高程序数据的读取效率,尤其是针对一些需要较大开销的资源,缓存显得尤其重要。

缓存分类

不考虑网络缓存的话,一般的数据缓存环境主要有:内存、NSUserDefaults、磁盘。

  1. 效率
    就效率而言将数据缓存到内存的效率应该是最高的,NSUserDefaults应该介于内存和磁盘之间(因为它也是持久化到默认的数据库的,不过Apple可能对其做了优化处理,这里没有通过测试验证,哪位朋友有兴趣可以做个小测试)。存入磁盘效率肯定是最低的。
  2. 各种方案的实现形式及优缺点
    缓存到内存一般有两种方式:集合类(如:NSMutableDictionary),和NSCache。由于App的内存是很珍贵的资源,所以如果要缓存很大量的数据肯定要持久化到磁盘。其中使用集合类不是线程安全的,在多线程环境下需要加锁。但是NSCache是线程安全的,并且它提供了一些其他好用的功能,来帮助程序员提高编码的效率和程序的健壮性,所以一般我们的内存缓存建议使用NSCache。
    缓存到磁盘一般有:数据文件、数据库等方式,该方案的缺点就是效率低下,但是优点是足够大(哈哈,很大的哦)。
    NSUserDefaults也是一种线程安全的缓存机制,但是它的局限性在于不适合缓存大的数据,而且对于自定义的数据类型需要实现NSCoding(归档)协议。
  3. 小结
    一般的缓存模块的设计是综合上面几种方式协调使用的,比如对于程序全局都要使用的关键性的少量的数据,我们可以放到NSUserDefaults里面,这样公开一个key,程序的任何地方再读写缓存的时候都很方便。对于复杂的对象类型,我们先考虑放到内存中缓存起来(刚刚创建或者刚刚使用的数据要优先使用内存的缓存),一般我们根据程序的自身逻辑设置一个阈值,超过该阈值,我们就需要缓存到磁盘当中。读取的时候我们也按照先内存后磁盘的方式读取即可。

NSCache

NSCache的用法跟NSMutableDictionary非常类似,使用起来也很简单,但是他又有很多的特性帮我们轻松实现更高级的功能。

  1. NSCache具有自动删除的功能,当内存不足时会删除缓存中的数据以减少内存的开销
  2. NSCache是线程安全的,不需要加线程锁
  3. 键对象不会像 NSMutableDictionary 中那样被复制。(键不需要实现 NSCopying 协议)

NSCache的声明

@interface NSCache  : NSObject {
@private
    id _delegate;
    void *_private[5];
    void *_reserved;
}
@property (copy) NSString *name;
@property (nullable, assign) id delegate;
- (nullable ObjectType)objectForKey:(KeyType)key;
- (void)setObject:(ObjectType)obj forKey:(KeyType)key; // 0 cost
- (void)setObject:(ObjectType)obj forKey:(KeyType)key cost:(NSUInteger)g;
- (void)removeObjectForKey:(KeyType)key;
- (void)removeAllObjects;
@property NSUInteger totalCostLimit;    // limits are imprecise/not strict
@property NSUInteger countLimit;    // limits are imprecise/not strict
@property BOOL evictsObjectsWithDiscardedContent;
@end
  • NSCacheDelegate类型的delegate属性,NSCacheDelegate声明如下:
@protocol NSCacheDelegate 
@optional
- (void)cache:(NSCache *)cache willEvictObject:(id)obj;
@end

该代理方法在缓存对象即将被清理的时候调用,第一个参数是NSCache对象,当一个代理是多个NSCache对象的代理是,可以通过名字判断到底属于哪个。注意此时不能修改NSCache对象。第二个参数是即将被移除的对象,通常此时我们需要把这个对象持久化到磁盘当中。

  • totalCostLimit属性:用于指定花费大小的限制,花费由setObject:forKey:cost:函数的cost指定。
  • countLimit属性:缓存对象个数的限制,与花费限制共同作用,以先到者为准。
  • evictsObjectsWithDiscardedContent属性:当被缓存的对象销毁时,是否将其从缓存中移除,默认为真
    方法就不一一介绍了,无非就是往缓存里添加对象,或者移除对象的行为。

验证totalCostLimit的Demo

    NSCache *cache = [[NSCache alloc] init];
    cache.countLimit = 5;
    cache.totalCostLimit = 5;
    for (int i = 0; i < 5; i++) {
        [cache setObject:[NSString stringWithFormat:@"%d",i] forKey:[NSString stringWithFormat:@"%d",i] cost:2];
    }
    for (int i = 0; i < 5; i++) {
        NSString *item = [cache objectForKey:[NSString stringWithFormat:@"%d",i]];
        NSLog(@"current item:%@",item);
    }

上述代码输出结果:

current item:(null)
current item:(null)
current item:(null)
current item:3
current item:4

从上面的输出结果可以看到添加的每个对象的cost是2,由于totalCostLimit设置为5,所以缓存只能存放2个对象,其他对象均被按顺序移除。

写文章真的好累!!!希望路过的给个赞呗!

你可能感兴趣的:(缓存组件中的NSCache)