EGOCache如何檢測緩存時間過期

jopen 9年前發布 | 14K 次閱讀 EGOCache iOS開發 移動開發

在上一篇文章中:EGOCache緩存框架詳細講解 提到EGOCache可以設定緩存過期時間,默認是1天。查看了一下EGOCache源碼,設置默認時間:

    [self setDefaultTimeoutInterval:86400];

    //86400 = 24 * 60 * 60 剛好是一天時間。

EGOCache為什么要提供設定緩存過期時間呢?或者說設定緩存過期時間有什么好處呢?我覺得最大的好處就是可以定時清除緩存。可以設置某一項的緩存時間,很方便管理緩存。

那么問題來了:

  1. EGOCache是怎么檢測緩存過期時間的呢?
  2. 檢測到時間過期之后,什么時候觸發刪除緩存項的?

帶著這兩個問題,我們來繼續分析。

你會怎么實現

記得在公司里,老板經常會舉這樣的例子:

某某同志,剛來我們公司的時候,遇到問題就知道抱怨。從來不知道去思考怎么解決,只知道把問題拋給領導。工作半年下來,成長了很多。現在碰到問題,不僅把問題拋出來,而且還提供了自己的解決方案...

類似的例子,相信大家都聽過。同樣,既然前面我們提出這兩個問題,我們也先來思考一下,如果我們來做該怎么解決?

如果讓我來寫的話,我腦海里初步實現方法有幾個:

  1. 通過定時器來輪詢,每隔一段時間檢測一次。
  2. 寫一個while循環來檢測。
  3. 每次去讀取緩存項的時候,判斷緩存時間有沒有過期。沒過期,就返回讀取的緩存項;否則,返回nil。

當然,還有一些方法,不一一例舉了。仔細想想,這些方法弊端很容易顯露出來。

  1. 為了小小的緩存時間,就用定時器輪詢,顯然是資源浪費
  2. 跟方法1差不多。
  3. 每次讀取的時候判斷是否過期,如果一直不讀取,app的緩存會越來越大,也不可取。

這些方法都被排除了,還有好的方法嗎?繼續往下看:

EGOCache是怎么實現的?

仔細查看EGOCache源碼,發現在initWithCacheDirectory:方法里,每次初始化EGOCache實例對象的時,會遍歷一遍plist文件中所有已存在的緩存項,拿每個緩存項的時間和當前時間作比較,緩存項過期時間早于當前時間,則刪除對應緩存文件,并刪除 plist 文件中對應 key 的記錄。

具體實現代碼如下:

讀取緩存項信息

_cacheInfo = [[NSDictionary dictionaryWithContentsOfFile:cachePathForKey(_directory, @"EGOCache.plist")] mutableCopy];

if(!_cacheInfo) {
    _cacheInfo = [[NSMutableDictionary alloc] init];
}

獲取當前時間的NSTimeInterval

NSTimeInterval now = [[NSDate date] timeIntervalSinceReferenceDate];

聲明removedKeys保存過期的緩存項對應的key

NSMutableArray* removedKeys = [[NSMutableArray alloc] init];

遍歷緩存項信息并判斷緩存時間

for(NSString* key in _cacheInfo) {
    //判斷緩存項過期時間是否早于當前時間
    if([_cacheInfo[key] timeIntervalSinceReferenceDate] <= now) {
        //如果緩存項過期時間早于當前時間,移除緩存項
        [[NSFileManager defaultManager] removeItemAtPath:cachePathForKey(_directory, key) error:NULL];
        //把過期的緩存項對于的key保存到removedKeys里面
        [removedKeys addObject:key];
    }
}

刪除過期緩存項對于的key

[_cacheInfo removeObjectsForKeys:removedKeys];

看到這些,是不是覺得人家思路特牛叉,反正,我是覺得這個作者不簡單。到這一步就解決了嗎?

EGOCache還做了什么?

細心的童鞋會發現:EGOCache是個單列類,也就是說整個程序應用周期只初始化一次。

+ (instancetype)globalCache {
    static id instance;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[[self class] alloc] init];
    });

    return instance;
}

每次初始化的時候去判斷了緩存項是否過期,這樣做非常正確。思考一個場景:

  1. 用戶打開app,EGOCache被初始化,并判斷了緩存項是否過期。
  2. 如果剛好有一些緩存項在EGOCache被初始化之后過期。這個時候我們依然可以讀到這個緩存項。這就不對了。

繼續分析EGOCache源碼發現,EGOCache在讀取一個緩存項的時候,先判斷緩存項是否存在,然后讀取緩存項(注意:是讀取EGOCache初始化的時候沒有過期的緩存項,并沒有說現在沒有過期),最后去判斷讀取到的緩存項跟當前時間相比是否過期.

具體實現如下:

- (BOOL)hasCacheForKey:(NSString*)key {
    //讀取EGOCache初始化的時候沒有過期的緩存項
    NSDate* date = [self dateForKey:key];
    if(date == nil) return NO;
    //判斷讀取到的緩存項當前是否過期
    if([date timeIntervalSinceReferenceDate] < CFAbsoluteTimeGetCurrent()) return NO;

    return [[NSFileManager defaultManager] fileExistsAtPath:cachePathForKey(_directory, key)];
}

- (NSDate*)dateForKey:(NSString*)key {
    __block NSDate* date = nil;

    dispatch_sync(_frozenCacheInfoQueue, ^{
        date = (self.frozenCacheInfo)[key];
    });

    return date;
}

EGOCache檢測緩存時間過期的思路值得學習,以后遇到類似場景,完全可以借鑒。


原文鏈接:http://www.superqq.com/blog/2015/07/02/egocacheru-he-jian-ce-huan-cun-shi-jian-guo-qi/

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!