客戶端許多場景下使用 Key-Value 存儲就能很好的滿足需求,通常我們會使用 NSUserDefaults,但 NSUserDefaults 不支持加密,持久化速度慢。
統一存儲的 Key-Value 存儲提供接口存儲:NSInteger、long long(在 64 位系統上與 NSInteger 相同)、BOOL、double、NSString 等類型的 PList 對象,支持 NSCoding 的對象,以及可通過反射轉換成 JSON 表達的 Objective-C 對象,極大簡化客戶端持久化對象的復雜度。
關于 Key-Value 存儲中大部分接口的說明,請參考 APSharedPreferences.h
頭文件方法描述。
存儲基本類型
統一存儲提供下列接口存儲基本類型。
- (NSInteger)integerForKey:(NSString*)key business:(NSString*)business;
- (NSInteger)integerForKey:(NSString*)key business:(NSString*)business defaultValue:(NSInteger)defaultValue; // 當數據不存在時返回默認值
- (void)setInteger:(NSInteger)value forKey:(NSString*)key business:(NSString*)business;
- (long long)longLongForKey:(NSString*)key business:(NSString*)business;
- (long long)longLongForKey:(NSString*)key business:(NSString*)business defaultValue:(long long)defaultValue; // 當數據不存在時返回默認值
- (void)setLongLong:(long long)value forKey:(NSString*)key business:(NSString*)business;
- (BOOL)boolForKey:(NSString*)key business:(NSString*)business;
- (BOOL)boolForKey:(NSString*)key business:(NSString*)business defaultValue:(BOOL)defaultValue; // 當數據不存在時返回默認值
- (void)setBool:(BOOL)value forKey:(NSString*)key business:(NSString*)business;
- (double)doubleForKey:(NSString*)key business:(NSString*)business;
- (double)doubleForKey:(NSString*)key business:(NSString*)business defaultValue:(double)defaultValue; // 當數據不存在時返回默認值
- (void)setDouble:(double)value forKey:(NSString*)key business:(NSString*)business;
其中 defaultValue
參數為數據不存在時返回的默認值。
存儲 Objective-C 對象
接口說明
統一存儲提供下列接口存儲 Objective-C 對象。
- (NSString*)stringForKey:(NSString*)key business:(NSString*)business;
- (NSString*)stringForKey:(NSString*)key business:(NSString*)business extension:(APDataCrypt*)extension;
- (void)setString:(NSString*)string forKey:(NSString*)key business:(NSString*)business;
- (void)setString:(NSString*)string forKey:(NSString*)key business:(NSString*)business extension:(APDataCrypt*)extension;
- (id)objectForKey:(NSString*)key business:(NSString*)business;
- (id)objectForKey:(NSString*)key business:(NSString*)business extension:(APDataCrypt*)extension;
- (void)setObject:(id)object forKey:(NSString*)key business:(NSString*)business;
- (void)setObject:(id)object forKey:(NSString*)key business:(NSString*)business extension:(APDataCrypt*)extension;
- (BOOL)setObject:(id)object forKey:(NSString*)key business:(NSString*)business extension:(APDataCrypt*)extension options:(APDataOptions)options;
- (void)archiveObject:(id)object forKey:(NSString*)key business:(NSString*)business;
- (void)archiveObject:(id)object forKey:(NSString*)key business:(NSString*)business extension:(APDataCrypt*)extension;
- (BOOL)archiveObject:(id)object forKey:(NSString*)key business:(NSString*)business extension:(APDataCrypt*)extension options:(APDataOptions)options;
- (void)saveJsonObject:(id)object forKey:(NSString*)key business:(NSString*)business;
- (void)saveJsonObject:(id)object forKey:(NSString*)key business:(NSString*)business extension:(APDataCrypt*)extension;
- (BOOL)saveJsonObject:(id)object forKey:(NSString*)key business:(NSString*)business extension:(APDataCrypt*)extension options:(APDataOptions)options;
setString & stringForKey
保存 NSString 時,推薦使用 setString
,stringForKey
接口,名稱上更有解釋性。
如果數據未加密,使用這個接口存儲的字符串,可以通過 SQLite DB 查看器看到,更直觀。使用 setObject
保存的字符串會首先通過 Property List 轉成 NSData 再保存到數據庫里。
setObject
保存 Property List 對象時,建議使用 setObject
,這樣效率最高。
Property List 對象: NSNumber、NSString、NSData、NSDate、NSArray、NSDictionary,NSArray 和 NSDictionary 里的子對象也只能是 PList 對象。
使用 setObject
保存 Property List 后,使用 objectForKey
取到的對象是 Mutable 的。下面代碼里拿到的 savedArray
是 NSMutableArray
。
NSArray* array = [[NSArray alloc] initWithObjects:@"str", nil];
[APCommonPreferences setObject:array forKey:@"array" business:@"biz"];
NSArray* savedArray = [APCommonPreferences objectForKey:@"array" business:@"biz"];
archiveObject
對于支持 NSCoding 協議的 Objective-C 對象,統一存儲調用系統的 NSKeyedArchiver
將對象轉成 NSData 并進行持久化。
Property List 對象也可以使用這個接口,但效率比較低,不推薦。
saveJsonObject
當一個 Objective-C 對象既不是 Property List 對象,也不支持 NSCoding 協議時,可以使用這個方法進行持久化。
該方法通過運行時動態反射,將 Objective-C 對象映射成 JSON 字符串。但不是所有 Objective-C 對象都可以使用該方法保存,比如含有 C 結構體指針屬性的 Objective-C 對象,互相引用的 Objective-C 對象,屬性里有字典或數組的 Objective-C 對象。
objectForKey
統一存儲保存 Objective-C 對象數據時,會同時記錄它的歸檔方式,取對象統一使用 objectForKey
。
使用 setString
保存的字符串需要使用 stringForKey
獲取。
數據加密
使用默認加密
帶 extension
的接口支持加密,傳入 APDataCrypt
結構體。
APDefaultEncrypt
為默認加密方法,為 AES 對稱加密。
APDefaultDecrypt
為默認解密方法,與 APDefaultEncrypt
使用相同密鑰。
通常情況下,使用統一存儲提供的默認加密即可,如下所示:
[APUserPreferences setObject:aObject forKey:@"key" business:@"biz" extension:APDefaultEncrypt()];
id obj = [APUserPreferences objectForKey:@"key" business:@"biz" extension:APDefaultDecrypt()];
// or
id obj = [APUserPreferences objectForKey:@"key" business:@"biz"];
因為使用的是默認加密,所以取數據的接口可以省略 extension
參數。
使用自定義加密方法
如果業務有更高的加密安全要求,可以自己實現 APDataCrypt
結構體,并指定加密、解密的函數指針。但請保證加密與解密方法對應,這樣才能正確保存、還原數據。
基礎類型加密
如果想加密存儲 BOOL、NSInteger、double、long long 類型的對象,可以把它們轉成字符串,或放到 NSNumber 里,再調用 setString
、setObject
接口即可。
指定 options
typedef NS_OPTIONS (unsigned int, APDataOptions)
{
// 這兩個選項不要在接口中使用,是標識數據的加密屬性的,請使用 extension 來傳遞加密方法
APDataOptionDefaultEncrypted = 1 << 0, // 這個選項不要傳,傳了也沒效果,統一存儲會使用接口里的 extension 來做加密的判斷,而不是 options
APDataOptionCustomEncrypted = 1 << 1, // 這個選項不要傳,傳了也沒效果,統一存儲會使用接口里的 extension 來做加密的判斷,而不是 options
// 標識該數據在清理緩存時可被清除,這里用 unsinged int 強轉 1,為因為某些編譯選項下,右邊的 1<<31 不能按照 unsigned int 來計算,導致賦值失敗
APDataOptionPurgeable = (unsigned int)1 << 31,
};
可以在 setObject
、archiveObject
、saveJsonObject
三個方法中指定 options。
APDataOptionPurgeable
指該數據可以在數據清理時自動清除,詳見 數據清理。