本文假設(shè)你對(duì)weex有基本的了解!(本文的目的是講解iOS的一種緩存方案實(shí)現(xiàn)螃成,weex的部分不懂并無(wú)大礙。如果不關(guān)心,可以直接從iOS實(shí)現(xiàn)的部分開始閱讀)
weex Module的簡(jiǎn)單介紹
言歸正題脓诡,先從官方文檔了解Storage的使用方式。
我們發(fā)現(xiàn)媒役,客戶端主要提供了4個(gè)API:
- setItem(key, value, callback)
- getItem(key, callback)
- removeItem(key, callback)
- length(callback)
下面祝谚,我們逐一分析他們的具體實(shí)現(xiàn)。
Storage 實(shí)現(xiàn)
1. 存儲(chǔ)數(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"});
}
}
代碼解析:
- 首先酣衷,在這個(gè)方法之前踊跟,檢驗(yàn)了key的類型。只能是NSString或NSNumber鸥诽,且不能為空商玫,并去除了空格和回車字符。
- 其次牡借,根據(jù)key的
name
在沙盒的~/Document
目錄下生成一個(gè)wxStorage
目錄拳昌。文件名是name
的MD5值。wxStorage
目錄下存放數(shù)據(jù)內(nèi)容時(shí)會(huì)生成3個(gè)文件钠龙,分別是:wxStorage.plist
炬藤,wxStorage.info.plist
,wxStorage.index.plist
碴里。第一個(gè)存放數(shù)據(jù)鍵值對(duì)沈矿;第二個(gè)存放數(shù)據(jù)的額外信息,如存放時(shí)間咬腋、數(shù)據(jù)長(zhǎng)度羹膳、索引信息等;第三個(gè)存放key值根竿,用于遍歷陵像。 - 如果data的內(nèi)容length小于Limit(weex指定為1024byte),則將該key/value直接寫入
memory
字典寇壳。memory
是weex自身實(shí)現(xiàn)的一個(gè)線程安全型的字典醒颖。隨后,方法會(huì)依次把數(shù)據(jù)寫入上一步所說(shuō)的3個(gè)plist文件中壳炎。檢查storage
是否超出Limit限制泞歉。如果是,則刪除部分內(nèi)容。 - 如果data的內(nèi)容length大于Limit腰耙,先將該key/value存放于
globalCache
中偿洁。這是一個(gè)基于NSCache實(shí)現(xiàn)的全局緩存,目的是為了數(shù)據(jù)能在內(nèi)存中存儲(chǔ)沟优,被高效地使用涕滋。存儲(chǔ)的步驟和上面的“小數(shù)據(jù)”一樣。不同的是挠阁,大數(shù)據(jù)不是直接存放在plist中宾肺。plist中存放了一個(gè)假數(shù)據(jù),并和之前一樣同步的被寫入plist文件侵俗。而真數(shù)據(jù)是額外開了一個(gè)隊(duì)列锨用,異步寫入的。filePath
即是當(dāng)前目錄隘谣,文件名為key的MD5值增拥。
總結(jié)一下:數(shù)據(jù)先是存放在了一個(gè)線程安全的字典中;以1024byte為分界線寻歧,如果是“小數(shù)據(jù)”掌栅,則同步寫入一個(gè)管理文件;如果是“大數(shù)據(jù)”码泛,則異步寫入文件猾封,每個(gè)數(shù)據(jù)單獨(dú)存放為一個(gè)文件。
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});
}
}
了解了如何存儲(chǔ)噪珊,獲取就相對(duì)簡(jiǎn)單了晌缘。依次,先從memory
字典中找痢站,然后去globalCache
中找磷箕,最后去filePath
下找;如果都沒(méi)找到阵难,則移除該key
岳枷,并把文件中和該key
相關(guān)的內(nèi)容都刪除了。
總結(jié)
對(duì)比YYCache的實(shí)現(xiàn)多望,weex的storage模塊實(shí)現(xiàn)比較簡(jiǎn)單嫩舟,條理清晰氢烘。在簡(jiǎn)單的數(shù)據(jù)緩存上完全夠用了怀偷。