weex的數(shù)據(jù)緩存模塊之storage實(shí)現(xiàn)源碼閱讀

本文假設(shè)你對weex有基本的了解?。ū疚牡哪康氖侵v解iOS的一種緩存方案實(shí)現(xiàn),weex的部分不懂并無大礙。如果不關(guān)心,可以直接從iOS實(shí)現(xiàn)的部分開始閱讀)

weex Module的簡單介紹

言歸正題,先從官方文檔了解Storage的使用方式。
我們發(fā)現(xiàn),客戶端主要提供了4個API:

  • setItem(key, value, callback)
  • getItem(key, callback)
  • removeItem(key, callback)
  • length(callback)

下面,我們逐一分析他們的具體實(shí)現(xiàn)。

Storage 實(shí)現(xiàn)

1. 存儲數(shù)據(jù)

先上代碼:

- (void)setObject:(NSString *)obj forKey:(NSString *)key persistent:(BOOL)persistent callback:(WXModuleCallback)callback {
    NSString *filePath = [WXStorageModule filePathForKey:key];
    if (obj.length <= WXStorageLineLimit) {
        if ([WXStorageNullValue isEqualToString:self.memory[key]]) {
            [[WXUtility globalCache] removeObjectForKey:key];
            [[NSFileManager defaultManager] removeItemAtPath:filePath error:nil];
        }
        self.memory[key] = obj;
        NSDictionary *dict = [self.memory copy];
        [self write:dict toFilePath:[WXStorageModule filePath]];
        [self setInfo:@{@"persistent":@(persistent),@"size":@(obj.length)} ForKey:key];
        [self updateIndexForKey:key];
        [self checkStorageLimit];
        if (callback) {
            callback(@{@"result":@"success"});
        }
        return;
    }
    
    [[WXUtility globalCache] setObject:obj forKey:key cost:obj.length];
    
    if (![WXStorageNullValue isEqualToString:self.memory[key]]) {
        self.memory[key] = WXStorageNullValue;
        NSDictionary *dict = [self.memory copy];
        [self write:dict toFilePath:[WXStorageModule filePath]];
    }
    
    dispatch_async([WXStorageModule storageQueue], ^{
        [obj writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:NULL];
    });
    
    [self setInfo:@{@"persistent":@(persistent),@"size":@(obj.length)} ForKey:key];
    [self updateIndexForKey:key];
    
    [self checkStorageLimit];
    if (callback) {
        callback(@{@"result":@"success"});
    }
}

代碼解析:

  • 首先,在這個方法之前,檢驗(yàn)了key的類型。只能是NSString或NSNumber,且不能為空,并去除了空格和回車字符。
  • 其次,根據(jù)key的name在沙盒的~/Document目錄下生成一個wxStorage目錄。文件名是name的MD5值。wxStorage目錄下存放數(shù)據(jù)內(nèi)容時會生成3個文件,分別是:wxStorage.plist,wxStorage.info.plist,wxStorage.index.plist。第一個存放數(shù)據(jù)鍵值對;第二個存放數(shù)據(jù)的額外信息,如存放時間、數(shù)據(jù)長度、索引信息等;第三個存放key值,用于遍歷。
  • 如果data的內(nèi)容length小于Limit(weex指定為1024byte),則將該key/value直接寫入memory字典。memory是weex自身實(shí)現(xiàn)的一個線程安全型的字典。隨后,方法會依次把數(shù)據(jù)寫入上一步所說的3個plist文件中。檢查storage是否超出Limit限制。如果是,則刪除部分內(nèi)容。
  • 如果data的內(nèi)容length大于Limit,先將該key/value存放于globalCache中。這是一個基于NSCache實(shí)現(xiàn)的全局緩存,目的是為了數(shù)據(jù)能在內(nèi)存中存儲,被高效地使用。存儲的步驟和上面的“小數(shù)據(jù)”一樣。不同的是,大數(shù)據(jù)不是直接存放在plist中。plist中存放了一個假數(shù)據(jù),并和之前一樣同步的被寫入plist文件。而真數(shù)據(jù)是額外開了一個隊(duì)列,異步寫入的。filePath即是當(dāng)前目錄,文件名為key的MD5值。

總結(jié)一下:數(shù)據(jù)先是存放在了一個線程安全的字典中;以1024byte為分界線,如果是“小數(shù)據(jù)”,則同步寫入一個管理文件;如果是“大數(shù)據(jù)”,則異步寫入文件,每個數(shù)據(jù)單獨(dú)存放為一個文件。

2. 獲取數(shù)據(jù)

- (void)getItem:(NSString *)key callback:(WXModuleCallback)callback
{
    if ([self checkInput:key]) {
        if (callback) {
            callback(@{@"result":@"failed",@"data":@"key must a string or number!"}); // forgive my english
        }
        return;
    }
    
    if ([key isKindOfClass:[NSNumber class]]) {
        key = [((NSNumber *)key) stringValue]; // oh no!
    }
    
    if ([WXUtility isBlankString:key]) {
        if (callback) {
            callback(@{@"result":@"failed",@"data":@"invalid_param"});
        }
        return ;
    }
    
    NSString *value = [self.memory objectForKey:key];
    if ([WXStorageNullValue isEqualToString:value]) {
        value = [[WXUtility globalCache] objectForKey:key];
        if (!value) {
            NSString *filePath = [WXStorageModule filePathForKey:key];
            NSString *contents = [WXUtility stringWithContentsOfFile:filePath];
            if (contents) {
                [[WXUtility globalCache] setObject:contents forKey:key cost:contents.length];
                value = contents;
            }
        }
    }
    if (!value) {
        [self executeRemoveItem:key];
        if (callback) {
            callback(@{@"result":@"failed",@"data":@"undefined"});
        }
        return;
    }
    [self updateTimestampForKey:key];
    [self updateIndexForKey:key];
    if (callback) {
        callback(@{@"result":@"success",@"data":value});
    }
}

了解了如何存儲,獲取就相對簡單了。依次,先從memory字典中找,然后去globalCache中找,最后去filePath下找;如果都沒找到,則移除該key,并把文件中和該key相關(guān)的內(nèi)容都刪除了。

總結(jié)

對比YYCache的實(shí)現(xiàn),weex的storage模塊實(shí)現(xiàn)比較簡單,條理清晰。在簡單的數(shù)據(jù)緩存上完全夠用了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容