數(shù)據(jù)持久化方案一----NSUserDefaults(偏好設(shè)置)

一、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ù)庫處理吧

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市春贸,隨后出現(xiàn)的幾起案子混萝,更是在濱河造成了極大的恐慌,老刑警劉巖萍恕,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逸嘀,死亡現(xiàn)場離奇詭異,居然都是意外死亡允粤,警方通過查閱死者的電腦和手機(jī)崭倘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門翼岁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人司光,你說我怎么就攤上這事琅坡。” “怎么了残家?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵榆俺,是天一觀的道長。 經(jīng)常有香客問我坞淮,道長茴晋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任回窘,我火速辦了婚禮诺擅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘毫玖。我一直安慰自己掀虎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布付枫。 她就那樣靜靜地躺著烹玉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪阐滩。 梳的紋絲不亂的頭發(fā)上二打,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音掂榔,去河邊找鬼继效。 笑死,一個(gè)胖子當(dāng)著我的面吹牛装获,可吹牛的內(nèi)容都是我干的瑞信。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼穴豫,長吁一口氣:“原來是場噩夢啊……” “哼凡简!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起精肃,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤秤涩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后司抱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體筐眷,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年习柠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了匀谣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片照棋。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖武翎,靈堂內(nèi)的尸體忽然破棺而出必怜,到底是詐尸還是另有隱情,我是刑警寧澤后频,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站暖途,受9級(jí)特大地震影響卑惜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜驻售,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一露久、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧欺栗,春花似錦毫痕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至类腮,卻和暖如春臊泰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蚜枢。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工缸逃, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人厂抽。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓需频,卻偏偏與公主長得像,于是被迫代替她去往敵國和親筷凤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子昭殉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 關(guān)于首選項(xiàng)和設(shè)置 首選項(xiàng)是您持久存儲(chǔ)的信息,并用于配置您的應(yīng)用程序嵌施。應(yīng)用程序通常會(huì)向用戶公開偏好設(shè)置颂翼,以便他們自定...
    nicedayCoco閱讀 987評(píng)論 0 0
  • 概述: NSUserDefaults,官網(wǎng)上的定義是一個(gè)用戶默認(rèn)數(shù)據(jù)庫的接口翰意,在應(yīng)用程序的啟動(dòng)過程中,持久地存儲(chǔ)鍵...
    淺_若清風(fēng)閱讀 7,147評(píng)論 1 9
  • 文件 歸檔(NSKeyedArchiver) 屬性列表(NSUserDefaults) 數(shù)據(jù)庫(SQLite、Co...
    零度_不結(jié)冰閱讀 8,629評(píng)論 0 2
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,089評(píng)論 1 32
  • 羅輯思維 羅振宇說成年人學(xué)習(xí)要注意5個(gè)關(guān)鍵詞:人格贤姆、概念、縫合钧惧、碎片、目標(biāo)礁阁。 還舉個(gè)例子,一個(gè)成年人想學(xué)編程族奢,買了...
    小殊閱讀 97評(píng)論 0 0