YYKVStorageItem文件
先看頭文件
@interface YYKVStorageItem : NSObject
@property (nonatomic, strong) NSString *key; ///< key
@property (nonatomic, strong) NSData *value; ///< value
@property (nonatomic, strong) NSString *filename; ///< filename (nil if inline)
@property (nonatomic, assign) int size; ///< value's size in bytes
@property (nonatomic, assign) int modTime; ///< 最后修改時間戳
@property (nonatomic, assign) int accessTime; ///< 最后訪問時間戳
@property (nonatomic, strong) NSData *extendedData; ///< extended data (nil if no extended data)
@end
YYKVStorageItem指的是每一個存儲的單元,也可以理解為某一個鍵值對,只是這個存儲單元的屬性更加完善,還有修改時間戳和訪問時間戳,以及補充的數據,這個補充的數據有什么意義呢,我的理解是補充說明這個存儲單元。
YYKVStorage文件
typedef NS_ENUM(NSUInteger, YYKVStorageType) {
/// The `value` is stored as a file in file system.
YYKVStorageTypeFile = 0,
/// The `value` is stored in sqlite with blob type.
YYKVStorageTypeSQLite = 1,
/// The `value` is stored in file system or sqlite based on your choice.
YYKVStorageTypeMixed = 2,
};
關于YYKVStorageType,作者分析了YYKVStorageTypeSQLite,YYKVStorageTypeFile這兩種存儲方式的效率問題,得出了這樣的結論:如果你想儲存大量的比較小的數據(如聯系人緩存),使用YYKVStorageTypeSQLite來獲得更好的性能。如果你想存儲大文件(如圖像緩存),使用YYKVStorageTypeFile來獲得更好的性能。當然也可以使用YYKVStorageTypeMixed為每個項目選擇存儲類型。
YYKVStorage和YYKVStorageItem的關系
YYKVStorage像一個manager用來管理每一個YYKVStorageItem,我們可以通過YYKVStorage來操作單個的YYKVStorageItem。比如保存,移除,獲取等等。大家可以對照YYKVStorage文件,里面有非常多的相關操作函數。
保存一個緩存項
- (BOOL)saveItemWithKey:(NSString *)key value:(NSData *)value filename:(NSString *)filename extendedData:(NSData *)extendedData {
if (key.length == 0 || value.length == 0) return NO;
if (_type == YYKVStorageTypeFile && filename.length == 0) {
return NO;
}
if (filename.length) {
if (![self _fileWriteWithName:filename data:value]) {
return NO;
}
if (![self _dbSaveWithKey:key value:value fileName:filename extendedData:extendedData]) {
[self _fileDeleteWithName:filename];
return NO;
}
return YES;
} else {
if (_type != YYKVStorageTypeSQLite) {
NSString *filename = [self _dbGetFilenameWithKey:key];
if (filename) {
[self _fileDeleteWithName:filename];
}
}
return [self _dbSaveWithKey:key value:value fileName:nil extendedData:extendedData];
}
}
保存一個緩存項的操作步驟:
1.先判斷key,value是否為空
2.filename不為空的情況下,先將NSData寫入磁盤文件,然后向數據庫插入一條磁盤緩存文件的表記錄
filename為空的情況下,根據key查詢表中記錄緩存項的filename字段,刪除查詢到的filename對
應的緩存文件,更新key對應的緩存表記錄的filename字段,清空為nil。
刪除多個緩存項
- (BOOL)removeItemForKeys:(NSArray *)keys {
if (keys.count == 0) return NO;
switch (_type) {
case YYKVStorageTypeSQLite: {
return [self _dbDeleteItemWithKeys:keys];
} break;
case YYKVStorageTypeFile:
case YYKVStorageTypeMixed: {
NSArray *filenames = [self _dbGetFilenameWithKeys:keys];
for (NSString *filename in filenames) {
[self _fileDeleteWithName:filename];
}
return [self _dbDeleteItemWithKeys:keys];
} break;
default: return NO;
}
}
刪除多個緩存項的操作步驟:
1.先判斷數組是否為空
2.判斷緩存方式是哪一種
如果是sqlite存儲,刪除sqlite里對應的緩存項
如果是文件存儲,先獲取所有文件名,然后刪除
如果是混合模式,重復上述步驟
刪除所有項
- (BOOL)removeAllItems {
if (![self _dbClose]) return NO;
[self _reset];
if (![self _dbOpen]) return NO;
if (![self _dbInitialize]) return NO;
return YES;
}
刪除所有目錄的操作步驟是:
1.首先關閉數據庫,并確認已經關閉
2.格式化數據庫,移除db.sqlite,db.sqlite-shm,db.sqlite-wal文件(這三個文件具體是什么職責后面詳細介紹),將所有磁盤文件移動到Trash目錄下,然后將刪除Trash目錄下文件的操作放到子線程隊列上異步執行
3.初始化數據庫
補充:在沙盒下的SQLite數據庫包含三個文件:db.sqlite,db.sqlite-shm,db.sqlite-wal。
db.sqlite 存放數據庫本身的數據: 表、表記錄、index、sequence …
db.sqlite-shm 存放的是Shared-Memory Files,數據庫必須開啟WAL模式,當多個線程/進程訪問同一個數據庫時,讓每一個數據庫連接可以進行內存數據共享,隨著 db-wal文件創建而創建,刪除而刪除.
db.sqlite-wal Write-Ahead Log (WAL) Files WAL的全稱是Write Ahead Logging,它是很多數據庫中用于實現原子事務的一種機制。同樣數據庫必須開啟WAL模式,用于當數據庫實現實現原子事務,當創建第一個數據庫連接時創建 db-wal文件,當最后一個數據庫連接關閉時刪除 db-wal文件.
查詢某個項
- (YYKVStorageItem *)getItemForKey:(NSString *)key {
if (key.length == 0) return nil;
YYKVStorageItem *item = [self _dbGetItemWithKey:key excludeInlineData:NO];
if (item) {
[self _dbUpdateAccessTimeWithKey:key];
if (item.filename) {
item.value = [self _fileReadWithName:item.filename];
if (!item.value) {
[self _dbDeleteItemWithKey:key];
item = nil;
}
}
}
return item;
}
查詢的步驟是:
1.先判斷key是否為空
2.通過Key查找到對應的緩存項
3.如果查找成功,更新訪問時間,然后通過文件名,讀取數據,如果數據為空,則通過key刪除對應的文件
查詢多個項
- (NSArray *)getItemForKeys:(NSArray *)keys {
if (keys.count == 0) return nil;
NSMutableArray *items = [self _dbGetItemWithKeys:keys excludeInlineData:NO];
if (_type != YYKVStorageTypeSQLite) {
for (NSInteger i = 0, max = items.count; i < max; i++) {
YYKVStorageItem *item = items[i];
if (item.filename) {
item.value = [self _fileReadWithName:item.filename];
if (!item.value) {
if (item.key) [self _dbDeleteItemWithKey:item.key];
[items removeObjectAtIndex:i];
i--;
max--;
}
}
}
}
if (items.count > 0) {
[self _dbUpdateAccessTimeWithKeys:keys];
}
return items.count ? items : nil;
}
查詢多個緩存項步驟:
1.先判斷需要查找的緩存數組是否為空
2.然后在數據庫里拿到所有緩存項
3.遍歷出每個緩存項,并確保值存在,不存在的刪除掉
4.最后更新所有緩存項的訪問時間。
微博賬號:梅嘉慶(點擊關注)