一、NSUserDefaults是專門用來存儲(chǔ)App配置信息的栓辜,一般不要在偏好設(shè)置中保存其他數(shù)據(jù)卜范。是一個(gè)plist刹悴,名字為Bundle identifier名字,如cn.com.xiaoli.XLDemo.plist
二行楞、存儲(chǔ)位置
沙盒--> Library-->Preferences: *.plist
NSString *preferencePath = NSSearchPathForDirectoriesInDomains(NSPreferencePanesDirectory, NSUserDomainMask, YES).firstObject;
三、支持持久化類型
NSArray(含NSMutableArray)土匀、NSDictionary(含NSMutableDictionary)子房、NSData(含NSMutableData)、NSString(含NSMutableString)恒削、NSNumber池颈、NSDate、BOOL钓丰。但存儲(chǔ)的對(duì)象全是不可變的躯砰。
四、NSUserDefaults的域:
UserDefaults數(shù)據(jù)庫中其實(shí)是由多個(gè)層級(jí)的域組成的携丁,當(dāng)你讀取一個(gè)鍵值的數(shù)據(jù)時(shí)琢歇,NSUserDefaults從上到下透過域的層級(jí)尋找正確的值,不同的域有不同的功能梦鉴,有些域是可持久的李茫,有些域則不行。默認(rèn)包含五個(gè)Domain肥橙,如下:
1魄宏、參數(shù)域( argument domain)有最高優(yōu)先權(quán)
2、應(yīng)用域(application domain)是最重要的域存筏,它存儲(chǔ)著你app通過NSUserDefaults set...forKey添加的設(shè)置
3宠互、全局域(global domain)則存儲(chǔ)著系統(tǒng)的設(shè)置
4、語言域(language-specific domains)則包括地區(qū)椭坚、日期等
5予跌、注冊域(registration domain)僅有較低的優(yōu)先權(quán),只有在應(yīng)用域沒有找到值時(shí)才從注冊域去尋找
例如善茎,當(dāng)某個(gè)界面是第一次運(yùn)行時(shí)券册,這時(shí)的key值(鍵)所對(duì)應(yīng)的值還不存在,所以NSUserDefaults對(duì)象會(huì)使用默認(rèn)值為0垂涯。但是對(duì)于某些設(shè)置烁焙,可能需要臨時(shí)的、非0的默認(rèn)值(如"出廠設(shè)置")耕赘,否則應(yīng)用將無法正確的運(yùn)行骄蝇。一般默認(rèn)值都是存放于注冊域中。默認(rèn)情況下鞠苟,應(yīng)用域是空的,沒有鍵也沒有值。當(dāng)用戶第一次修改某個(gè)設(shè)置時(shí)当娱,相應(yīng)的值會(huì)通過指定的鍵加入應(yīng)用域吃既。當(dāng)通過NSUserDefaults對(duì)象獲取某個(gè)設(shè)置的值時(shí),該對(duì)象先會(huì)在應(yīng)用域查找跨细,如果沒有鹦倚,NSUserDefaults則會(huì)在注冊域中查找并返回默認(rèn)值。查詢順序:參數(shù)域 -> 應(yīng)用域 -> 全局域 -> 語言域 ->注冊域冀惭。
五震叙、api使用方法(類似NSMutableDictionary)
//獲取標(biāo)準(zhǔn)用戶默認(rèn)對(duì)象(配置為搜索當(dāng)前應(yīng)用程序搜索列表的NSUserDefaults的全局實(shí)例)
@property (class, readonly, strong) NSUserDefaults *standardUserDefaults;
//重置
+ (void)resetStandardUserDefaults;
// 用應(yīng)用程序和當(dāng)前用戶的默認(rèn)值初始化用戶默認(rèn)對(duì)象
- (nullable instancetype)initWithSuiteName:(nullable NSString *)suitename API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0)) NS_DESIGNATED_INITIALIZER;
- (nullable id)initWithUser:(NSString *)username API_DEPRECATED("Use -init instead", macos(10.0,10.9), ios(2.0,7.0), watchos(2.0,2.0), tvos(9.0,9.0));
//存
- (void)setObject:(nullable id)value forKey:(NSString *)defaultName;
- (void)setInteger:(NSInteger)value forKey:(NSString *)defaultName;
- (void)setFloat:(float)value forKey:(NSString *)defaultName;
- (void)setDouble:(double)value forKey:(NSString *)defaultName;
- (void)setBool:(BOOL)value forKey:(NSString *)defaultName;
- (void)setURL:(nullable NSURL *)url forKey:(NSString *)defaultName API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));
存完后要調(diào)用synchronize方法,如果沒有調(diào)用散休,系統(tǒng)會(huì)根據(jù)I/O情況不定時(shí)刻地保存到文件中媒楼,會(huì)造成數(shù)據(jù)丟失。所以如果需要立即寫入文件的就必須調(diào)用synchronize方法戚丸。
//取
- (nullable id)objectForKey:(NSString *)defaultName;
- (nullable NSString *)stringForKey:(NSString *)defaultName;
- (nullable NSArray *)arrayForKey:(NSString *)defaultName;
- (nullable NSDictionary<NSString *, id> *)dictionaryForKey:(NSString *)defaultName;
- (nullable NSData *)dataForKey:(NSString *)defaultName;
- (nullable NSArray<NSString *> *)stringArrayForKey:(NSString *)defaultName;
- (NSInteger)integerForKey:(NSString *)defaultName;
- (float)floatForKey:(NSString *)defaultName;
- (BOOL)boolForKey:(NSString *)defaultName;
- (nullable NSURL *)URLForKey:(NSString *)defaultName API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));
//刪(同樣調(diào)用synchronize方法)
// -removeObjectForKey: is equivalent to -[... setObject:nil forKey:defaultName]
- (void)removeObjectForKey:(NSString *)defaultName;
注冊默認(rèn)值
//將指定字典的內(nèi)容添加到注冊域
- (void)registerDefaults:(NSDictionary<NSString *, id> *)registrationDictionary;
//維護(hù)套間
//將指定的域名插入到接收方的搜索列表中
- (void)addSuiteNamed:(NSString *)suiteName;
//從接收器的搜索列表中移除指定的域名
- (void)removeSuiteNamed:(NSString *)suiteName;
返回包含搜索列表中域中所有鍵值對(duì)的聯(lián)合的字典
- (NSDictionary<NSString *, id> *)dictionaryRepresentation;
維護(hù)易失性域
//易失性域名
@property (readonly, copy) NSArray<NSString *> *volatileDomainNames;
//返回指定的易失性域的字典
- (NSDictionary<NSString *, id> *)volatileDomainForName:(NSString *)domainName;
//為指定的易失性域設(shè)置字典
- (void)setVolatileDomain:(NSDictionary<NSString *, id> *)domain forName:(NSString *)domainName;
//從用戶的默認(rèn)值中移除指定的易失性域
- (void)removeVolatileDomainForName:(NSString *)domainName;
//維護(hù)持久域
//返回當(dāng)前持久域名的數(shù)組(不推薦使用
- (NSArray *)persistentDomainNames API_DEPRECATED("Not recommended", macos(10.0,10.9), ios(2.0,7.0), watchos(2.0,2.0), tvos(9.0,9.0));
//返回指定域默認(rèn)值的字典表示形式
- (nullable NSDictionary<NSString *, id> *)persistentDomainForName:(NSString *)domainName;
//為指定的持久域設(shè)置字典
- (void)setPersistentDomain:(NSDictionary<NSString *, id> *)domain forName:(NSString *)domainName;
//從用戶的默認(rèn)值中移除指定的持久域的內(nèi)容
- (void)removePersistentDomainForName:(NSString *)domainName;
//訪問托管環(huán)境密鑰
//返回一個(gè)布爾值划址,該值指示指定密鑰是否由管理員管理
- (BOOL)objectIsForcedForKey:(NSString *)key;
//返回一個(gè)布爾值,該值指示指定域中的密鑰是否由管理員管理
- (BOOL)objectIsForcedForKey:(NSString *)key inDomain:(NSString *)domain;
//域
//由所有應(yīng)用程序所看到的默認(rèn)值組成的域(全局域)
FOUNDATION_EXPORT NSString * const NSGlobalDomain;
//從應(yīng)用程序的參數(shù)解析默認(rèn)值組成的域(參數(shù)域)
FOUNDATION_EXPORT NSString * const NSArgumentDomain;
//由一組臨時(shí)缺省值組成的域限府,其值可以由應(yīng)用程序設(shè)置夺颤,以確保搜索始終是成功的(注冊域)
FOUNDATION_EXPORT NSString * const NSRegistrationDomain;
//相關(guān)通知
//當(dāng)用戶默認(rèn)數(shù)據(jù)中存儲(chǔ)更多數(shù)據(jù)時(shí)
FOUNDATION_EXPORT NSNotificationName const NSUserDefaultsSizeLimitExceededNotification API_AVAILABLE(ios(9.3), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);
//當(dāng)設(shè)置了云默認(rèn)時(shí),但沒有登錄iCloud用戶
FOUNDATION_EXPORT NSNotificationName const NSUbiquitousUserDefaultsNoCloudAccountNotification API_AVAILABLE(ios(9.3), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);
//當(dāng)用戶更改主iCloud帳戶時(shí)
FOUNDATION_EXPORT NSNotificationName const NSUbiquitousUserDefaultsDidChangeAccountsNotification API_AVAILABLE(ios(9.3), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);
//發(fā)布時(shí)胁勺,默認(rèn)完成下載數(shù)據(jù)世澜,無論是第一次設(shè)備連接到一個(gè)iCloud帳戶,或當(dāng)用戶切換他們的主要iCloud帳戶
FOUNDATION_EXPORT NSNotificationName const NSUbiquitousUserDefaultsCompletedInitialSyncNotification API_AVAILABLE(ios(9.3), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);
//在當(dāng)前進(jìn)程中更改用戶默認(rèn)值時(shí)發(fā)布
FOUNDATION_EXPORT NSNotificationName const NSUserDefaultsDidChangeNotification;
例子:
//1.獲得NSUserDefaults文件
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
//2.向文件中寫入內(nèi)容
[userDefaults setObject:@"qwert" forKey:@"testKey"];
//2.1立即同步
[userDefaults synchronize];
//3.讀取文件
NSString *testKey = [userDefaults objectForKey:@"testKey"];
NSLog(@"%@", testKey);
//4.刪除文件
[userDefaults removeObjectForKey:@"testKey"];
[userDefaults synchronize];
五署穗、思考與棄用
項(xiàng)目中的一些簡易信息是使用NSUserDefaults存的寥裂,最近收到用戶反饋之前存的東西找不到了,檢查了代碼很多次也沒有查出問題蛇捌,便懷疑NSUserDefaults方式的持久化出問題了抚恒。
經(jīng)過實(shí)際測試如果存儲(chǔ)后立即退出或者意外閃退,NSUserDefaults的數(shù)據(jù)會(huì)丟失络拌。
翻看文檔是異步存儲(chǔ):
/*!
-setObject:forKey: immediately stores a value (or removes the value if nil is passed as the value) for the provided key in the search list entry for the receiver's suite name in the current user and any host, then asynchronously stores the value persistently, where it is made available to other processes.
*/
- (void)setObject:(nullable id)value forKey:(NSString *)defaultName;
//舊版本中的強(qiáng)制同步在iOS14中不建議用俭驮,iOS15中已經(jīng)棄用
/*!
-synchronize is deprecated and will be marked with the API_DEPRECATED macro in a future release.
-synchronize blocks the calling thread until all in-progress set operations have completed. This is no longer necessary. Replacements for previous uses of -synchronize depend on what the intent of calling synchronize was. If you synchronized...
- ...before reading in order to fetch updated values: remove the synchronize call
- ...after writing in order to notify another program to read: the other program can use KVO to observe the default without needing to notify
- ...before exiting in a non-app (command line tool, agent, or daemon) process: call CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication)
- ...for any other reason: remove the synchronize call
*/
- (BOOL)synchronize;
建議換個(gè)輕量型數(shù)據(jù)庫處理吧