IOS緩存管理之YYCache使用詳解
前言:
最近一直在致力于為公司app添加緩存功能,為了尋找一個最佳方案,這幾天先做個技術預研,經過這兩天的查找資料基本上確定了兩個開源框架進行選擇,這兩個開源框架分別是:PINCache、YYCache,上篇已經簡單介紹了PINCache使用,本篇主要來學習一下YYCache的使用方式,以及和PINCache性能的簡單對比。
關于YYCache
1. 內存緩存(YYMemoryCache)
存儲的單元是_YYLinkedMapNode,除了key和value外,還存儲了它的前后Node的地址_prev,_next.整個實現基于_YYLinkedMap,它是一個雙向鏈表,除了存儲了字典_dic外,還存儲了頭結點和尾節(jié)點.它實現的功能很簡單,就是:有新數據了插入鏈表頭部,訪問過的數據結點移到頭部,內存緊張時把尾部的結點移除.就這樣實現了淘汰算法.因為內存訪問速度很快,鎖占用的時間少,所以用的速度最快的OSSpinLockLock
2. 硬盤緩存(YYDiskCache)
采用的是文件和數據庫相互配合的方式.有一個參數inlineThreshold,默認20KB,小于它存數據庫,大于它存文件.能獲得效率的提高.key:path,value:cache存儲在NSMapTable里.根據path獲得cache,進行一系列的set,get,remove操作更底層的是YYKVStorage,它能直接對sqlite和文件系統(tǒng)進行讀寫.每次內存超過限制時,select key, filename, size from manifest order by last_access_time desc limit ?1會根據時間排序來刪除最近不常用的數據.硬盤訪問的時間比較長,如果用OSSpinLockLock鎖會造成CPU消耗過大,所以用的dispatch_semaphore_wait來做.
YYCache使用
1.同步方式
//模擬數據 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];
2.異步方式
//模擬數據 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"); } }];
YYCache緩存LRU清理
LRU(Least Recently Used)算法大家都比較熟悉,翻譯過來就是“最近最少使用”,LRU緩存就是使用這種原理實現,簡單的說就是緩存一定量的數據,當超過設定的閾值時就把一些過期的數據刪除掉,比如我們緩存10000條數據,當數據小于10000時可以隨意添加,當超過10000時就需要把新的數據添加進來,同時要把過期數據刪除,以確保我們最大緩存10000條,那怎么確定刪除哪條過期數據呢,采用LRU算法實現的話就是將最老的數據刪掉。接下來我們測試一下
YYCache *yyCache=[YYCache cacheWithName:@"LCJCache"]; [yyCache.memoryCache setCountLimit:50];//內存最大緩存數據個數 [yyCache.memoryCache setCostLimit:1*1024];//內存最大緩存開銷 目前這個毫無用處 [yyCache.diskCache setCostLimit:10*1024];//磁盤最大緩存開銷 [yyCache.diskCache setCountLimit:50];//磁盤最大緩存數據個數 [yyCache.diskCache setAutoTrimInterval:60];//設置磁盤lru動態(tài)清理頻率 默認 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)(120 * 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:@"whoislcj%d",i]; id vuale=[yyCache objectForKey:key]; NSLog(@"key :%@ value : %@",key ,vuale); } });
YYCache和PINCache一樣并沒有實現基于最大內存開銷進行LRU,不過YYCache實現了最大緩存數據個數進行LRU清理,這一點也是選擇YYCache原因之一,對于YYCache磁盤LRU清理并不是及時清理,而是后臺開啟一個定時任務進行RLU清理操作,定時時間默認是60s。
YYCache與PINCache對比
對于我這里的使用場景大部分用于緩存json字符串,我這里就以存儲字符串來對比一下寫入與讀取效率
1.寫入性能對比
YYCache
//模擬數據 NSString *value=@"I want to know who is lcj ?"; //模擬一個key NSString *key=@"key"; //YYCache YYCache *yyCache=[YYCache cacheWithName:@"LCJCache"]; //寫入數據 CFAbsoluteTime start = CFAbsoluteTimeGetCurrent(); [yyCache setObject:value forKey:key withBlock:^{ CFAbsoluteTime end = CFAbsoluteTimeGetCurrent(); NSLog(@" yyCache async setObject time cost: %0.5f", end - start); }]; CFAbsoluteTime start1 = CFAbsoluteTimeGetCurrent(); [yyCache setObject:value forKey:key]; CFAbsoluteTime end1 = CFAbsoluteTimeGetCurrent(); NSLog(@" yyCache sync setObject time cost: %0.5f", end1 - start1);
運行結果
PINCache
//PINCache //模擬數據 NSString *value=@"I want to know who is lcj ?"; //模擬一個key NSString *key=@"key"; PINCache *pinCache=[PINCache sharedCache]; //寫入數據 CFAbsoluteTime start = CFAbsoluteTimeGetCurrent(); [pinCache setObject:value forKey:key block:^(PINCache * _Nonnull cache, NSString * _Nonnull key, id _Nullable object) { CFAbsoluteTime end = CFAbsoluteTimeGetCurrent(); NSLog(@" pincache async setObject time cost: %0.5f", end - start); }]; CFAbsoluteTime start1 = CFAbsoluteTimeGetCurrent(); [pinCache setObject:value forKey:key]; CFAbsoluteTime end1 = CFAbsoluteTimeGetCurrent(); NSLog(@" pinCache sync setObject time cost: %0.5f", end1 - start1);
運行結果
通過上面的測試可以看出 同樣大小的數據,無論同步方式還是異步方式,YYCache性能都要由于PINCache。
2.讀取性能對比
YYCache
YYCache *yyCache=[YYCache cacheWithName:@"LCJCache"]; //模擬一個key NSString *key=@"key"; CFAbsoluteTime start = CFAbsoluteTimeGetCurrent(); //讀取數據 [yyCache objectForKey:key withBlock:^(NSString * _Nonnull key, id<NSCoding> _Nonnull object) { CFAbsoluteTime end = CFAbsoluteTimeGetCurrent(); NSLog(@" yyCache async objectForKey time cost: %0.5f", end - start); }]; CFAbsoluteTime start1 = CFAbsoluteTimeGetCurrent(); [yyCache objectForKey:key]; CFAbsoluteTime end1 = CFAbsoluteTimeGetCurrent(); NSLog(@" yyCache sync objectForKey time cost: %0.5f", end1 - start1);
運行結果:
PINCache
PINCache *pinCache=[PINCache sharedCache]; //模擬一個key NSString *key=@"key"; CFAbsoluteTime start = CFAbsoluteTimeGetCurrent(); //讀取數據 [pinCache objectForKey:key block:^(PINCache * _Nonnull cache, NSString * _Nonnull key, id _Nullable object) { CFAbsoluteTime end = CFAbsoluteTimeGetCurrent(); NSLog(@" pincache async objectForKey time cost: %0.5f", end - start); }] ; CFAbsoluteTime start1 = CFAbsoluteTimeGetCurrent(); [pinCache objectForKey:key]; CFAbsoluteTime end1 = CFAbsoluteTimeGetCurrent(); NSLog(@" pinCache objectForKey time cost: %0.5f", end1 - start1);
運行結果:
通過運行結果,在讀取方面YYCache也是優(yōu)于PINCache。
總結:
經過一番查閱資料和自己寫例子測試,最終項目中決定使用YYCache進行緩存管理。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
iOS移動端(H5)alert/confirm提示信息去除網址(URL)
這篇文章主要介紹了iOS移動端(H5)alert/confirm提示信息去除網址URL,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-11-11iOS使用 CABasicAnimation 實現簡單的跑馬燈(無cpu暴漲)
本篇文章主要介紹了iOS使用 CABasicAnimation 實現簡單的跑馬燈(無cpu暴漲),具有一定的參考價值,有興趣的可以了解一下。2017-01-01舉例講解Objective-C中@property屬性的用法
這篇文章主要介紹了Objective-C中@property屬性的用法,包括@property的屬性關鍵字的整理,需要的朋友可以參考下2016-03-03iOS App開發(fā)中UIViewController類的使用教程
UIViewController是iOS中控制視圖的關鍵所在,這里我們將針對UIViewController的聲明周期與主要屬性和方法,來總結iOS App開發(fā)中UIViewController類的使用教程2016-07-07iOS使用WKWebView加載HTML5不顯示屏幕寬度的問題解決
這篇文章主要介紹了iOS使用WKWebView加載HTML5不顯示屏幕寬度的問題解決,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-12-12