YYCache源码分析(一)

作者: 汉斯哈哈哈 | 来源:发表于2016-06-09 21:40 被阅读6886次

    iOS 开发中总会用到各种缓存,YYCache或许是你最好的选择。性能上有优势,用法也很简单。作者ibireme曾经对比过同类轮子:http://blog.ibireme.com/2015/10/26/yycache/

    1.简单架构图

    2.YYCache.h方法分析

    
    @interface YYCache : NSObject
    // 读取当前数据库名称
    @property (copy, readonly) NSString *name;
    
    // memoryCache内存缓存,diskCache文件缓存
    @property (strong, readonly) YYMemoryCache *memoryCache;
    @property (strong, readonly) YYDiskCache *diskCache;
    
    // 可通过下面三种方法来实例化YYCache对象
    - (nullable instancetype)initWithName:(NSString *)name;
    - (nullable instancetype)initWithPath:(NSString *)path NS_DESIGNATED_INITIALIZER;
    + (nullable instancetype)cacheWithPath:(NSString *)path;
    
    // 禁止通过下面两个方式实例化对象
    - (instancetype)init UNAVAILABLE_ATTRIBUTE;
    + (instancetype)new __attribute__((unavailable("new方法不可用,请用initWithName:")));
    
    // 通过key判断是否缓存了某个东西,第二个法是异步执行,异步回调
    - (BOOL)containsObjectForKey:(NSString *)key;
    - (void)containsObjectForKey:(NSString *)key withBlock:(nullable void(^)(NSString *key, BOOL contains))block;
    
    // 读--通过key读取缓存,第二个法是异步执行,异步回调
    - (nullable id<NSCoding>)objectForKey:(NSString *)key;
    - (void)objectForKey:(NSString *)key withBlock:(nullable void(^)(NSString *key, id<NSCoding> object))block;
    
    // 增、改--缓存对象(可缓存遵从NSCoding协议的对象),第二个法是异步执行,异步回调
    - (void)setObject:(nullable id<NSCoding>)object forKey:(NSString *)key;
    - (void)setObject:(nullable id<NSCoding>)object forKey:(NSString *)key withBlock:(nullable void(^)(void))block;
    
    // 删--删除缓存
    - (void)removeObjectForKey:(NSString *)key;
    - (void)removeObjectForKey:(NSString *)key withBlock:(nullable void(^)(NSString *key))block;
    - (void)removeAllObjects;
    - (void)removeAllObjectsWithBlock:(void(^)(void))block;
    - (void)removeAllObjectsWithProgressBlock:(nullable void(^)(int removedCount, int totalCount))progress
                                     endBlock:(nullable void(^)(BOOL error))end;
    
    @end
    
    

    3.YYCache使用

        // 0.初始化YYCache
        YYCache *cache = [YYCache cacheWithName:@"mydb"];
        // 1.缓存普通字符
        [cache setObject:@"汉斯哈哈哈" forKey:@"name"];
        NSString *name = (NSString *)[cache objectForKey:@"name"];
        NSLog(@"name: %@", name);
        // 2.缓存模型
        [cache setObject:(id<NSCoding>)model forKey:@"user"];
        // 3.缓存数组
        NSMutableArray *array = @[].mutableCopy;
        for (NSInteger i = 0; i < 10; i ++) {
            [array addObject:model];
        }
        // 异步缓存
        [cache setObject:array forKey:@"user" withBlock:^{
            // 异步回调
            NSLog(@"%@", [NSThread currentThread]);
            NSLog(@"array缓存完成....");
        }];
        // 延时读取
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            // 异步读取
            [cache objectForKey:@"user" withBlock:^(NSString * _Nonnull key, id<NSCoding>  _Nonnull object) {
                // 异步回调
                NSLog(@"%@", [NSThread currentThread]);
                NSLog(@"%@", object);
            }];
        });
    

    打印:

    2016-06-09 11:35:44.069 YYCache源码分析[13546:949048] <NSThread: 0x7ffd43f14840>{number = 2, name = (null)}
    2016-06-09 11:35:44.069 YYCache源码分析[13546:949048] array缓存完成....
    2016-06-09 11:35:44.386 YYCache源码分析[13546:949052] <NSThread: 0x7ffd43e01900>{number = 3, name = (null)}
    2016-06-09 11:35:44.386 YYCache源码分析[13546:949052] (
        "<UserModel: 0x7ffd44014310>",
        "<UserModel: 0x7ffd44014310>",
        "<UserModel: 0x7ffd44014310>",
        "<UserModel: 0x7ffd44014310>",
        "<UserModel: 0x7ffd44014310>",
        "<UserModel: 0x7ffd44014310>",
        "<UserModel: 0x7ffd44014310>",
        "<UserModel: 0x7ffd44014310>",
        "<UserModel: 0x7ffd44014310>",
        "<UserModel: 0x7ffd44014310>"
    )
    
    // 缓存实现,默认同时进行内存缓存与文件缓存
    - (void)setObject:(id<NSCoding>)object forKey:(NSString *)key {
        [_memoryCache setObject:object forKey:key];
        [_diskCache setObject:object forKey:key];
    }
    
    // 如果只想内存缓存,可以直接调用`memoryCache`对象
        YYCache *cache2 = [YYCache cacheWithName:@"mydb"];
        [cache2.memoryCache setObject:@24 forKey:@"age"];
        NSLog(@"age缓存在内存:%d", [cache2.memoryCache containsObjectForKey:@"age"]);
        NSLog(@"age缓存在文件:%d", [cache2.diskCache containsObjectForKey:@"age"]);
    
    

    打印:

    2016-06-09 21:23:24.326 YYCache源码分析[14512:1085375] age缓存在内存:1
    2016-06-09 21:23:24.326 YYCache源码分析[14512:1085375] age缓存在文件:0
    

    4.YYCache.h tips

    #if __has_include(<YYCache/YYCache.h>)
    #import <YYCache/YYMemoryCache.h>
    #import <YYCache/YYDiskCache.h>
    #import <YYCache/YYKVStorage.h>
    #elif __has_include(<YYWebImage/YYCache.h>)
    #import <YYWebImage/YYMemoryCache.h>
    #import <YYWebImage/YYDiskCache.h>
    #import <YYWebImage/YYKVStorage.h>
    #else
    #import "YYMemoryCache.h"
    #import "YYDiskCache.h"
    #import "YYKVStorage.h"
    #endif
    

    __has_include:用来检查Frameworks是否引入某个类,
    YYWebImage已经集成YYCache,如果导入过YYWebImage则无需重新导入YYCache

    NS_ASSUME_NONNULL_BEGIN
    @interface YYCache : NSObject
    ...
    - (nullable instancetype)initWithName:(NSString *)name;
    ...
    @end
    NS_ASSUME_NONNULL_END
    

    接口中 nullable 的是少数,一般都为nonnull,为了防止写一大堆 nonnull,Foundation供了一对宏NS_ASSUME_NONNULL_BEGINNS_ASSUME_NONNULL_END,包在里面的对象默认加 nonnull 修饰符,如果是nullable的,只需要把 nullable 的指出来就行

    - (instancetype)init UNAVAILABLE_ATTRIBUTE;
    + (instancetype)new UNAVAILABLE_ATTRIBUTE;
    

    command+鼠标左键UNAVAILABLE_ATTRIBUTE
    发现宏定义#define UNAVAILABLE_ATTRIBUTE __attribute__((unavailable)),
    __attribute__Clang提供的一种源码注解,方便开发者向编译器表达某种要求,括号里是传达某种命令.
    为方便使用,一些常用属性也被Cocoa定义成宏,
    比如UNAVAILABLE_ATTRIBUTENS_CLASS_AVAILABLE_IOS(9_0).
    unavailable告诉编译器该方法失效.
    在封装单例或初始化某个类前必须做一些事时,对一些方法禁用是非常不错的选择.
    还可以给个message提示:

    + (instancetype)alloc __attribute__((unavailable("alloc方法不可用,请用initWithName:")));
    - (instancetype)init __attribute__((unavailable("init方法不可用,请用initWithName:")));
    + (instancetype)new __attribute__((unavailable("new方法不可用,请用initWithName:")));
    - (instancetype)copy __attribute__((unavailable("copy方法不可用,请用initWithName:")));
    

    References

    http://blog.sunnyxx.com/2016/05/14/clang-attributes/
    http://blog.sunnyxx.com/2015/06/12/objc-new-features-in-2015/

    YYCache源码分析(二)
    YYCache源码分析(三)

    相关文章

      网友评论

      • CodeGeass:怎样获取yycache里面所有缓存?好像没有这个方法
      • 汉斯哈哈哈: // 异步缓存模型数组
        [cache setObject:self.personModels forKey:@"Persons" withBlock:^{
        // 异步回调
        NSLog(@"array缓存完成....");
        }];
        因为你的异步缓存的,所以读取的时候可能还没有缓存完成
      • Dariel:为什么cache有时能读出来,有时又不可以了?麻烦大神帮我看下https://pan.baidu.com/s/1mivY5Gs
      • PPAbner:你好!像你写的那样 [cache setObject:(id<NSCoding>)model forKey:@"user"];
        我模型遵循了NSCoding协议,并且在.m中实现了下面的方法才能取到值,上面的方法取的全是空!!【我想问,是不是下面的必须实现???如果属性很多,岂不是要一一写一遍?】
        -(instancetype)initWithCoder:(NSCoder *)aDecoder
        {
        if (self = [super init]) {
        self.name = [aDecoder decodeObjectForKey:@"name"];
        }
        return self;
        }
        -(void)encodeWithCoder:(NSCoder *)aCoder
        {
        [aCoder encodeObject:self.name forKey:@"name"];
        }
        PPAbner:@汉斯哈哈哈 谢谢!
        PPAbner:@汉斯哈哈哈 好的!可是runtime不会用!唉!
        汉斯哈哈哈:@PP_Abner 是滴,一定要实现,如果嫌麻烦,可以用runtime
      • 一抹相思泪成雨:问下 : 我已经创建cache,路径名称知道了,如何获取这个路径下,cache已占用的内存大小?
        汉斯哈哈哈:@Hoolink diskCache.totalCost
      • kakukeme:你好,这类图,使用什么画的,
        汉斯哈哈哈:@kakukeme Keynote
      • sculg:请问一下,你的错误提示翻译插件叫什么名字啊?
        sculg:@汉斯哈哈哈 那个翻译效果怎么实现的? :flushed:
        汉斯哈哈哈:@sculg 自带的,没用什么插件
      • 键盘风筝:在单利里面初始化YYCache,然后[[User Instance].cache setObject:(id<NSCoding>)result forKey:self.typeModel.name];存储,下次的时候读取[[User Instance].cache objectForKey:self.typeModel.name withBlock:^(NSString * _Nonnull key, id<NSCoding> _Nonnull object) {,
        但是当我结束程序,重新打开,缓存读取不到了
        重新天空之城:我也出现同样的问题
        汉斯哈哈哈:@liveCyz cache、result 、name 检查下,或到沙盒目录看是否缓存了数据,这段代码看不出出啥问题
      • 键盘风筝:你好,我想问一下初始化一次就读取不到之前的缓存,怎么办
        汉斯哈哈哈:@sculg ?
        sculg:@汉斯哈哈哈 麻烦提示一下怎么做到的? :pray:
        汉斯哈哈哈:@liveCyz 帖代码看看

      本文标题:YYCache源码分析(一)

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