iOS/NSUserDefaults详解

作者: sellse | 来源:发表于2015-12-09 02:07 被阅读52661次
    欢迎关注公众号: CodeReview

    关于NSUserDefaults首先要看苹果官方的定义

    NSUserDefault官方文档

    NSUserDefaults是什么,有什么用处

    对于应用来说,每个用户都有自己的独特偏好设置,而好的应用会让用户根据喜好选择合适的使用方式,把这些偏好记录在应用包的plist文件中,通过NSUserDefaults类来访问,这是NSUserDefaults的常用姿势。如果有一些设置你希望用户即使升级后还可以继续使用,比如玩游戏时得过的最高分、喜好和通知设置、主题颜色甚至一个用户头像,那么你可以使用NSUserDefaults来存储这些信息,如果有更多需求,可以了解数据持久化相关的知识。

    具体来说NSUserDefaults是iOS系统提供的一个单例类(iOS提供了若干个单例类),通过类方法standardUserDefaults可以获取NSUserDefaults单例。如:

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    

    NSUserDefaults单例以key-value的形式存储了一系列偏好设置,key是名称,value是相应的数据。存/取数据时可以使用方法objectForKey:setObject:forKey:来把对象存储到相应的plist文件中,或者读取,既然是plist文件,那么对象的类型则必须是plist文件可以存储的类型,正如官方文档中提到的——

    • NSData
    • NSString
    • NSNumber
    • NSDate
    • NSArray
    • NSDictionary

    而如果需要存储plist文件不支持的类型,比如图片,可以先将其归档为NSData类型,再存入plist文件,需要注意的是,即使对象是NSArrayNSDictionary,他们存储的类型也应该是以上范围包括的。

    存/读不同类型数据

    比如存/读一个整数、字符串和一张图片:

    ###存
    
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults setObject:@”jack“ forKey:@"firstName"];
    [defaults setInteger:10 forKey:@"Age"];
    
    UIImage *image =[UIImage imageNamed:@"somename"];
    NSData *imageData = UIImageJPEGRepresentation(image, 100);//把image归档为NSData
    [defaults setObject:imageData forKey:@"image"];
    
    [defaults synchronize];
    

    其中,方法synchronise是为了强制存储,其实并非必要,因为这个方法会在系统中默认调用,但是你确认需要马上就存储,这样做是可行的。

    ###读
    
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSString *firstName = [defaults objectForKey:@"firstName"]
    NSInteger age = [defaults integerForKey:@"Age"];
    
    NSData *imageData = [defaults dataForKey:@"image"];
    UIImage *image = [UIImage imageWithData:imageData];
    

    我们通过为三个数据设置key的方式把NSIntegerNSStringUIImage三种数据存储下来,其中图片是通过归档为NSData的方式进行存储的,除此之外,还可以被转为NSNumberNSString类型。顺便提一句,这里NSInteger没有星号,因为NSInteger根据系统是64位还是32位来判断自身是long还是int类型,并且它也不是一个标准Objective-C对象。

    简便方法存取不同类型数据

    由上边的例子可以看到一个方法-setInteger:,这跟常用的-setObject:相比设置类型更明确。其实,NSUserDefaults提供了若干简便方法可以存储某些常用类型的值,例如:

    - setBool:forKey:
    - setFloat:forKey:
    - setInteger:forKey:
    - setDouble:forKey:
    - setURL:forKey:
    

    这将使某些值的设置更简单。

    NSUserDefaults域

    考虑这么一种情况:

    BOOL showTutorialOnLaunch = [[NSUserDefaults standardUserDefaults] boolForKey:@"ShowTutorial"];
    

    这种情况下,当key值@“ShowTutorial”已设置后会运行正确。但如果默认数据库没有这个key的默认值时,将会返回NO,这或许就不一定是你需要的值了,因为无法区分NOno value,前一段所提到的简便方法大多有这种问题。
    解决方式:使用registerDefaults:方法
    首先创建一个包含用户偏好设置信息的DefaultPreferences.plist文件,添加到target中。在运行时,app就可以加载这个文件并且把内容传到registerDefaults :

    NSURL *defaultPrefsFile = [[NSBundle mainBundle]
    URLForResource:@"DefaultPreferences" withExtension:@"plist"];
    NSDictionary *defaultPrefs = [NSDictionary dictionaryWithContentsOfURL:defaultPrefsFile];
    [[NSUserDefaults standardUserDefaults] registerDefaults:defaultPrefs];
    

    注意需要在每次启动app并且没有在user defaules中读取数据的时候调用以上方法,因为registerDefaults:不能把这些默认数据存储到硬盘上,所以application:didFinishLaunchingWithOptions是最合适的地方。
    这样做的原因是:默认情况下,应用域是空的,没见键也没有值。当应用第一次设置某项用户偏好设置的值时,相应的值会通过指定的键加入应用域。当通过NSUserDefaults获取某项用户偏好设置的值时,NSUserDefaults会先在应用域中查找,如果找到了值,NSUserDefaults就会返回这个值。如果没有找到,NSUserDefaults就会在注册域中查找并返回默认值。

    user defaults数据库中其实是由多个层级的域组成的,当你读取一个键值的数据时,NSUserDefaults从上到下透过域的层级寻找正确的值,不同的域有不同的功能,有些域是可持久的,有些域则不行。

    • 应用域(application domain)是最重要的域,它存储着你app通过NSUserDefaults set...forKey添加的设置。
    • 注册域(registration domain)仅有较低的优先权,只有在应用域没有找到值时才从注册域去寻找。
    • 全局域(global domain)则存储着系统的设置
    • 语言域(language-specific domains)则包括地区、日期等
    • 参数域( argument domain)有最高优先权

    以上是对NSUserDefaults的总结,如果后续发现错误,将会第一时间更新。另外本文翻译和节选了三篇文章的观点和实例,以供参考:

    Storing Data with NSUserDefaults
    iOS SDK: Working with NSUserDefaults
    Handling Default Values With NSUserDefaults

    相关文章

      网友评论

      • 微小的沙土:那我自己创建一个plist文件,写入一个字典,跟这个userdefault有啥区别没
      • 上帝是个女孩丶:看的我是一脸懵逼,不知道楼主这么多喜欢哪来的。可能大家关注的点不同,至少我觉得registerDefaults这块讲的并不好。没有分析到registerDefaults的实际作用
        zheNgHH:注意需要在每次启动app并且没有在user defaules中读取数据的时候调用以上方法,因为registerDefaults:不能把这些默认数据存储到硬盘上,所以application:didFinishLaunchingWithOptions是最合适的地方。
        这段话没有理解 不能把默认数据存储到硬盘上 默认数据指的是userdefaults还是registerdefault的 ;存储到硬盘上的概念是什么
        糖炒0栗子:嗯, 也是这一块儿, 没看懂
        天真烂漫的孩子:大师果然一针见血!:smiley:
      • brance:请问楼主NSUserDefaults是同步还是异步呢?
        天真烂漫的孩子: -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.
        倒数第二句
      • myk: :+1:
      • e0c84f3c73bb: :+1:
        sellse:@Eunicon_17 😛欢迎关注我的公众号codereview,以后简书上经过修改的文章我会挪到公众号里哈哈
      • 彬哲:涨姿势
        sellse:@ZkeyDream :stuck_out_tongue_winking_eye:
      • 王大虾34::+1::+1::+1:
        sellse:@王大虾1号 谢谢
      • 秋桐树下:总结的很好 :+1:
        sellse:@LiXiangGuo 谢谢
      • 曾樑::+1::+1:
        sellse:@曾樑 :smile:

      本文标题:iOS/NSUserDefaults详解

      本文链接:https://www.haomeiwen.com/subject/medshttx.html