在iOS開發(fā)過程中,進(jìn)行數(shù)據(jù)本地存儲是主要的模塊之一,在進(jìn)行數(shù)據(jù)存儲的時候有多種情況夫晌,有些時候需要大型的數(shù)據(jù)存儲,毋容置疑需要用FMDB等數(shù)據(jù)庫存儲方法昧诱;但是有些時候存儲一些輕量級的數(shù)據(jù)晓淀,僅僅是存儲一些用戶的信息(用戶ID、賬號盏档、密碼凶掰、昵稱等)簡單數(shù)據(jù),使用NSUserDefaults是首選蜈亩,它是一個單例類懦窘,通過鍵值對的方式記錄設(shè)置,用于數(shù)據(jù)的本地永久化存儲勺拣,而且NSUserDefaults使用起來非常簡單方便奶赠。那么本篇文章就來深入的探討一下NSUserDefaults的使用。
一药有、NSUserDefaults的基本概念
簡單來說毅戈,NSUserDefaults是iOS系統(tǒng)提供的一個單例類,在整個程序中只有一個實例對象愤惰,通過類方法standardUserDefaults可以獲取NSUserDefaults單例苇经。eg:NSUserDefaults? *userDefaults = [NSUserDefaults standardUserDefaults];
NSUserDefaults單例是以key-value的形式存儲了一系列的偏好設(shè)置或者一些設(shè)置的記錄,key是鍵名稱宦言,value是對應(yīng)的數(shù)據(jù)扇单。存/取數(shù)據(jù)時可以使用方法objectForKey:和setObject:forKey:來把對象存儲到相應(yīng)的plist文件中,或者讀取奠旺。既然是plist文件蜘澜,那么對象的類型則必須是plist文件可以存儲的類型施流。
使用NSUserDefaults存儲自定義對象需要注意的是,NSUserDefaults只支持以下數(shù)據(jù)類型的存儲:NSString鄙信,NSDate瞪醋,NSNumber(NSInteger、float装诡、double)银受,NSArray,NSDictionary鸦采,BOOL. 如果想要存儲其他類型的數(shù)據(jù)宾巍,需要轉(zhuǎn)換為前面的類型,才能用NSUserDefaults存儲渔伯。注意:對相同的Key賦值約等于一次覆蓋顶霞,要保證每一個Key的唯一性。
可是還需要注意一點:如果把一個自定義的類存到一個NSArray里咱旱,然后再存到NSUserDefaults里也是不能操作成功的确丢。NSUserDefaults存儲的對象全是不可變的(這一點非常重要)绷耍,eg:如果我想存儲一個NSMutableArray對象吐限,我必須先創(chuàng)建一個不可變數(shù)組NSArray,再將它存入NSUserDefaults中去褂始;eg:如果設(shè)置一個可變的字符串值作為"StringDefault”你日后檢索字符串使用诸典,stringForKey:會是一成不變的。
如果需要存儲plist文件不支持的類型崎苗,比如圖片狐粱,可以先將其歸檔為NSData類型,再存入plist文件胆数,可是需要注意的是:即使對象是NSArray或NSDictionary肌蜻,他們存儲的類型也應(yīng)該是以上范圍所包括的。
二必尼、NSUserDefaults的基本用法
1蒋搜、NSUserDefaults的保存數(shù)據(jù):
NSUserDefaults *userDefaults =[NSUserDefaults standardUserDefaults];
[userDefaults setObject:firstName forKey:@”kUserDefaultNameKey“];
NSInteger age = [defaults integerForKey:@“kUserDefaultAgeKey”]; //這里的NSInteger沒有星號,是因為NSInteger是根據(jù)系統(tǒng)是64位還是32位來判斷自身是long還是int的類型判莉,并且它不是一個標(biāo)準(zhǔn)的Objective-C對象
?//UIImage做本地存儲的步驟豆挽,圖片是通過歸檔為NSData的方式進(jìn)行存儲的
UIImage *image=[[UIImage alloc]initWithContentsOfFile:@"photo.jpg"];
NSData *imageData = UIImageJPEGRepresentation(image, 100); //把UIImage對象轉(zhuǎn)換成NSData
[userDefaults synchronize]; //用synchronize方法把數(shù)據(jù)持久化到standardUserDefaults數(shù)據(jù)庫
2、NSUserDefaults的讀取數(shù)據(jù):
NSUserDefaults *userDefaults =[NSUserDefaults standardUserDefaults];
NSString *name = [userDefaults objectForKey:@"name"]; //根據(jù)鍵值取出name
NSData *imageData = [userDefaults dataForKey:@"image"];
UIImage *Image = [UIImage imageWithData:imageData]; //將NSData轉(zhuǎn)換為UIImage
3券盅、NSUserDefaults的清理數(shù)據(jù):
//方法一:
[[NSUserDefaults standardUserDefaults] removeObjectForKey:key];
[[NSUserDefaults standardUserDefaults]synchronize];
//方法二:
// 先將本地存儲轉(zhuǎn)化為字典帮哈,然后用for in遍歷刪除即可
?NSUserDefaults?*userDefaults = [NSUserDefaults?standardUserDefaults];
?NSDictionary?*dictionary = [userDefaults?dictionaryRepresentation];
?for(NSString?*key?in?[dictionary?allKeys]){
? ? ? [userDefaults?removeObjectForKey:key];
? ? ? [userDefaults?synchronize];
? }
4、不同類型數(shù)據(jù)存取不同
NSUserDefaults提供了若干簡便方法可以存儲某些常用類型的值锰镀,eg:
- setBool:forKey:
- setFloat:forKey:
- setInteger:forKey:
- setDouble:forKey:
- setURL:forKey:
三娘侍、NSUserDefaults的相關(guān)類方法
// 同步對共享對象的任何的更改默認(rèn)用戶和從內(nèi)存中釋放它
resetStandardUserDefaults
// 返回共享默認(rèn)對象
+ (NSUserDefaults *)standardUserDefaultsaddSuiteNamed:
// 插入到接收器的搜索列表中指定的域名
- (void)addSuiteNamed:( NSString *) suiteName
// 返回布爾值與指定鍵相關(guān)聯(lián)
- (BOOL)boolForKey:( NSString *) defaultName
// 返回與指定鍵相關(guān)聯(lián)的數(shù)組
- ( NSArray *)arrayForKey:( NSString *) defaultName
// 返回數(shù)據(jù)對象與指定鍵相關(guān)聯(lián)
- ( NSData *)dataForKey:( NSString *) defaultName
// 返回Dictionary對象與指定鍵相關(guān)聯(lián)
- ( NSDictionary *)dictionaryForKey:( NSString *) defaultName
// 返回一個字典咖刃,它包含在搜索列表中的域的所有鍵值對聯(lián)合( NSData , NSString 憾筏, NSNumber 僵缺, NSDate ,NSArray踩叭,或者NSDictionary )
- ( NSDictionary *)dictionaryRepresentation
// 消除了在標(biāo)準(zhǔn)應(yīng)用程序域指定的默認(rèn)鍵值
- (void)removeObjectForKey:( NSString *) defaultName
// 刪除指定的從用戶的默認(rèn)持久域的內(nèi)容
- (void)removePersistentDomainForName:( NSString *) domainName
// 設(shè)置指定的默認(rèn)鍵到指定的布爾值
- (void)setBool:(BOOL) value forKey:( NSString *) defaultName
// 設(shè)置為指定的字典持久域
- (void)setPersistentDomain:( NSDictionary *) domain forName:( NSString *) domainName
// 設(shè)置指定的默認(rèn)鍵到指定的URL值
- (void)setURL:( NSURL *) url forKey:( NSString *) defaultName
// 設(shè)置為指定的字典揮發(fā)性域
- (void)setVolatileDomain:( NSDictionary *) domain forName:( NSString *) domainName
// 返回與指定鍵關(guān)聯(lián)的字符串?dāng)?shù)組
- ( NSArray *)stringArrayForKey:( NSString *) defaultName
// 返回與指定鍵關(guān)聯(lián)的字符串
- ( NSString *)stringForKey:( NSString *) defaultName
//返回NSURL實例與指定鍵相關(guān)聯(lián)
- ( NSURL *)URLForKey:( NSString *) defaultName?
// 返回double值與指定鍵相關(guān)聯(lián)
- (double)doubleForKey:( NSString *) defaultName
// 返回浮點值與指定鍵相關(guān)聯(lián)
- (float)floatForKey:( NSString *) defaultName
// 返回NSUserDefaults對象初始化的用戶帳戶的默認(rèn)為指定的
- (id)initWithUser:( NSString *) username
// 返回整數(shù)值與指定鍵關(guān)聯(lián)
- ( NSInteger NSInteger )integerForKey:( NSString *) defaultName
// 判斷這個key是否存在
- (BOOL)objectIsForcedForKey:( NSString *) key
// 返回與指定默認(rèn)的第一個發(fā)生關(guān)聯(lián)的對象
- (id)objectForKey:( NSString *) defaultName
四裤园、NSUserDefaults的域
BOOL showTutorialOnLaunch = [[NSUserDefaults standardUserDefaults] boolForKey:@"ShowTutorial"];
這種情況下,當(dāng)key值@“ShowTutorial”已經(jīng)設(shè)置后就會運行正確韧拒,但如果默認(rèn)數(shù)據(jù)庫沒有這個key的默認(rèn)值時楼眷,就返回NO,這或許就不一定是需要的值了斤富,因為系統(tǒng)無法區(qū)分NO和no value膏潮。
以上解決方式:使用registerDefaults:方法
首先創(chuàng)建一個包含用戶偏好設(shè)置信息的DefaultPreferences.plist文件,添加到target中满力。在運行時焕参,App就可加載這個文件并且把內(nèi)容傳到registerDefaults :
NSURL *defaultPrefsFile = [[NSBundle mainBundle]
URLForResource:@"DefaultPreferences" withExtension:@"plist"];
NSDictionary *defaultPrefs = [NSDictionary dictionaryWithContentsOfURL:defaultPrefsFile];
[[NSUserDefaults standardUserDefaults] registerDefaults:defaultPrefs];
注意:需要在每次啟動app并且沒有在defaules中讀取數(shù)據(jù)的時候調(diào)用以上方法,因為registerDefaults:不能把這些默認(rèn)數(shù)據(jù)存儲到硬盤上油额,所以方法application:didFinishLaunchingWithOptions是最合適的位置叠纷。
這樣做法的原因:默認(rèn)情況下,應(yīng)用域是空的潦嘶,沒見鍵也沒有值涩嚣。當(dāng)應(yīng)用第一次設(shè)置某項用戶偏好設(shè)置的值時,相應(yīng)的值會通過指定的鍵加入應(yīng)用域掂僵。當(dāng)通過NSUserDefaults獲取某項用戶偏好設(shè)置的值時航厚,NSUserDefaults會先在應(yīng)用域中查找,如果找到了值锰蓬,NSUserDefaults就會返回這個值幔睬。如果沒找到,NSUserDefaults就會在注冊域中查找并返回默認(rèn)值芹扭。
域:
user defaults數(shù)據(jù)庫之中其實是由多個層級的域組成的麻顶,當(dāng)你讀取一個鍵值的數(shù)據(jù)時,NSUserDefaults從上到下透過域的層級尋找正確的值冯勉,不同的域有不同的功能澈蚌,有些域是可持久的,有些域則不行灼狰。
應(yīng)用域(application domain)是最重要的域宛瞄,它存儲著App通過NSUserDefaults set...forKey添加的設(shè)置;
注冊域(registration domain)僅有較低的優(yōu)先權(quán),只有在應(yīng)用域沒有找到值時才從注冊域去尋找份汗;
全局域(global domain)是存儲著系統(tǒng)的設(shè)置盈电;
語言域(language-specific domains)包括地區(qū)、日期等杯活;
參數(shù)域( argument domain)有最高優(yōu)先權(quán)匆帚。