IOS数据存储之NSUserDefaults

By | 2015年7月29日

概述

数据存储是开发中必不可少的一个功能,我们可以通过Sqlite数据库手动创建数据库,定义数据表;可以使用IOS的数据框架CoreData,更方便的操作数据库;也可以直接读写文件系统;这里将介绍另外一种常用的方法:使用NSUserDefaults类,以字典形式保存数据,IOS会自动把字典中的键值对转换成对应的XML文件(也就是plist文件),这个文件会被保存到APP的沙盒目录中(路径为Library/Preferences/plist文件名)。

NSUserDefaults为我们封装了读写plist文件的常用操作,我们可以使用它来保存一些简单的数据,比如系统配置,用户设置的参数之类的。

了解plist文件

在学习使用NSUserDefaults类的用法前,我们需要先了解plist文件是一个什么文件,它是什么格式,可以保存哪些格式的数据。这样才能明白NSUserDefaults是干嘛用的!

当我们新建一个项目后,会发现有一个Info.plist文件,里面有很多参数配置:

不要被这些复杂的参数所迷惑,这只是Xcode的为我们自动生成的一个plist文件,用来保存当前项目的一些配置,Xcode为它集成了很多可用的Key和Value,这些都是预置的。

我们所要了解一个文件的本质,只需使用文本编辑器打开plist文件(也可以使用Xcode自带的功能:右键plist文件,Open As,Source Code)。我用的是CotEditor

plist就是一个XML文件!key对应的就是键,string对应的就是值。

我们可以想像,NSUserDefaults为我们保存的就是这么一个xml文件,它的后缀名不叫xml而是plist,它会把我们代码中的Dictionary类型中的键值对转换成XML中对应的一个个节点。

plist中可以存储哪些数据类型

我们知道了plist是什么了之后,就该了解它的能力,也就是它能放哪些东西。

我们通过Xcode的plist文件编辑器,可以发现每一个键值对中间都有一个Type,不难理解这就是value的type,那有哪些type呢,右键即可:

集合类型(Array、Dictionary)

基本数据类型:(Boolean、Date、Number、String)

对象数据类型:(Data)

不难理解,也就这些数据可以被转换保存到一个纯文本文件(区别于二进制文件)中,其中Data类型稍微复杂点,在代码中我们会把某一个代码转换换NSData类型,然后IOS再把NSData转换为一长串乱码保存。

集合和基本数据类型对应的数据类型相信各位都清楚。

使用NSUserDefaults保存读取数据

接下来,看下如何使用NSUserDefaults这个类。在dash中,输如NSUserDefaults,根据几个分节点,我们可以知道,读数据用xxForKey,写数据用Setxx,删数据用removeObjectForKey

可以看到,读方法中有很多不同类型的方法,我们可以根据不同的数据类型来选择使用的读取方法,写方法也类似。

我们选中其中一个方法,可以看到它是一个普通的func,不是类方法,也就是说,我们需要使用NSUserDefault类的实例来调用。

有2中方法,第一种就是使用构造函数init(),第二种是调用standardUserDefaults属性获得一个默认的对象。

两者区别是,创建plist文件时所使用的Domain,使用init构造函数时,不考虑Domain环境,直接在当前App的沙盒目录下创建plist文件,使用项目的bundle identifier字符串作为plist文件的文件名。

使用standardUserDefaults时考虑Domain环境,默认也是也是使用bundle identifier作为plist文件的文件名。另外支持NSGlobalDomainNSRegistrationDomain,这一块就不详细展开了(因为我也还没理解…)

println(NSHomeDictionary())
let userDef = NSUserDefaults()
userDef.setInteger(1234, forKey: "count")
userDef.setObject("nice", forKey: "result")
userDef.setBool(true, forKey: "isShow")
userDef.setDouble(12.5, forKey: "point")

这段代码运行后,ios便会为我们创建一个plist文件,根据NSHomeDictionary方法返回的路径,打开目录,进入Library/Preferences目录:


使用Xcode打开:


写入数据,就这么简单,读取数据也同理:

 println(userDef.integerForKey("count"))
 println(userDef.objectForKey("result"))
 println(userDef.boolForKey("isShow"))
 println(userDef.doubleForKey("point"))

 Data类型的保存

NSUserDefaults支持保存对象类型,前提是需要把对象转为NSData

对象转换为NSData,我们把这个过程成为序列化或者叫编码~可以看这一篇详细介绍:《IOS中对象序列化与反序列化》

var person = Person()
person.name = "lijialong"
person.age = 26
let defa = NSUserDefaults()
//把Person对象保存到plist文件中,键值名为Person
defa.setObject(person, forKey: "Person")
defa.synchronize()

registerDefaults方法的使用

NSUserDefaults除了保存和读取功能外,还为我们提供了一个很便捷的方法:registerDefaults。

func registerDefaults(registrationDictionary: [NSObject : AnyObject])

它的参数是一个字典类型。它的作用是为定义一组默认的数据,仅仅是定义一组默认的数据…这些默认的数据是不会被保存到plist文件中的,我们需要手动变更这些数据然后保存。

举一个栗子,我们可以使用这个方法来确认App是否是第一次启动:

let defa = NSUserDefaults()
//注册一个默认值
defa.registerDefaults(["firstRun":true])
//从plist文件中读取内容,因为第一次启动还没有生成plist文件,所以读取上面注册的默认值
let isFirstRun = defa.boolForKey("firstRun")
//是第一次启动
if(isFirstRun){

    println("这是第一次启动")
    //手动把firstRun改为false,保存到plist中
    defa.setBool(false, forKey: "firstRun")
}
else{
    println("不是第一次启动")
}

registerDefaults方法中的字典数据是不会被保存到plist文件中的,当我们读取某个键值时,如果plist中没有找到,那么会从registerDefaults方法的字典参数中寻找对应的键值,拿到默认值。当我们做了相应处理后,再手动把这个键值内容保存到plist中,下次读取是就会直接读plist文件中的键值了,而不会读取registerDefaults参数中的字典内容了。