iOS 開發中總會用到各種快取,YYCache或許是你最好的選擇。效能上有優勢,用法也很簡單。作者ibireme
曾經對比過同類輪子:http://blog.ibireme.com/2015/10/26/yycache/
1.簡單架構圖
2.YYCache.h方法分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
@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使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
// 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); }]; }); |
列印:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
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>" ) |
1 2 3 4 5 |
// 快取實現,預設同時進行記憶體快取與檔案快取 - (void)setObject:(id<NSCoding>)object forKey:(NSString *)key { [_memoryCache setObject:object forKey:key]; [_diskCache setObject:object forKey:key]; } |
1 2 3 4 5 |
// 如果只想記憶體快取,可以直接呼叫`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"]); |
列印:
1 2 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#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
1 2 3 4 5 6 7 |
NS_ASSUME_NONNULL_BEGIN @interface YYCache : NSObject ... - (nullable instancetype)initWithName:(NSString *)name; ... @end NS_ASSUME_NONNULL_END |
介面中 nullable 的是少數,一般都為nonnull,為了防止寫一大堆 nonnull,Foundation供了一對巨集
NS_ASSUME_NONNULL_BEGIN
、NS_ASSUME_NONNULL_END
,包在裡面的物件預設加 nonnull 修飾符,如果是nullable的,只需要把 nullable 的指出來就行
1 2 |
- (instancetype)init UNAVAILABLE_ATTRIBUTE; + (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提示:
1234 + (instancetype)alloc __attribute__((unavailable("alloc方法不可用,請用initWithName:")));- (instancetype)init __attribute__((unavailable("init方法不可用,請用initWithName:")));+ (instancetype)new __attribute__((unavailable("new方法不可用,請用initWithName:")));- (instancetype)copy __attribute__((unavailable("copy方法不可用,請用initWithName:")));
本文只是簡單剖析,接下來會分析YYMemoryCache
實現原理.
References
http://blog.sunnyxx.com/2016/05/14/clang-attributes/
http://blog.sunnyxx.com/2015/06/12/objc-new-features-in-2015/
文章同步到微信公眾號:hans_iOS
有疑問可以在公眾號裡直接發