天天看點

YYCache 源碼分析(一)

iOS 開發中總會用到各種緩存,YYCache或許是你最好的選擇。性能上有優勢,用法也很簡單。作者ibireme 

1.簡單架構圖

YYCache 源碼分析(一)
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>"

)

// 緩存實作,預設同時進行記憶體緩存與檔案緩存

- (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

...

NS_ASSUME_NONNULL_END

接口中 nullable 的是少數,一般都為nonnull,為了防止寫一大堆 nonnull,Foundation供了一對宏NS_ASSUME_NONNULL_BEGIN、NS_ASSUME_NONNULL_END,包在裡面的對象預設加 nonnull 修飾符,如果是nullable的,隻需要把 nullable 的指出來就行

+ (instancetype)new UNAVAILABLE_ATTRIBUTE;

command+滑鼠左鍵UNAVAILABLE_ATTRIBUTE,

發現宏定義#define UNAVAILABLE_ATTRIBUTE __attribute__((unavailable)),

__attribute__是Clang提供的一種源碼注解,友善開發者向編譯器表達某種要求,括号裡是傳達某種指令.

為友善使用,一些常用屬性也被Cocoa定義成宏,

比如UNAVAILABLE_ATTRIBUTE、NS_CLASS_AVAILABLE_IOS(9_0).

unavailable告訴編譯器該方法失效.

在封裝單例或初始化某個類前必須做一些事時,對一些方法禁用是非常不錯的選擇.

還可以給個message提示:

+ (instancetype)alloc __attribute__((unavailable("alloc方法不可用,請用initWithName:")));

- (instancetype)init __attribute__((unavailable("init方法不可用,請用initWithName:")));

- (instancetype)copy __attribute__((unavailable("copy方法不可用,請用initWithName:")));

YYCache 源碼分析(一)
YYCache 源碼分析(一)

本文隻是簡單剖析,接下來會分析YYMemoryCache實作原理.

繼續閱讀