iOS数据存储之属性列表理解
数据存储简介
数据存储,即数据持久化,是指以何种方式保存应用程序的数据。
我的理解是,开发了一款应用之后,应用在内存中运行时会产生很多数据,这些数据在程序运行时和程序一起驻留在内存中,一旦程序运行结束从内存中退出后,这些数据也就相应消失了。等到再次运行程序的时候,之前的那些数据又要重新计算。但是对于一些应用,我们需要将程序产生的数据持久的保存起来,使得应用重启之后这些数据不会丢失,这时候就需要用到数据的持久化技术。
在iOS设备上实现数据持久化存储的方式有很多中机制,较为常见的有以下4种:
-
属性列表
-
对象归档
-
iOS的嵌入式关系数据库(SQLite)
-
苹果公司提供的持久化工具Core Data
除此之外还有NSUserDefaults、Preference等
属性列表
首先从属性列表开始学习
属性列表提供了一个方便的方式来存储简单的结构化数据。只有序列化对象才能存储在属性列表中。序列化对象是指可以被转换为字节流以便于存储到文件中或通过网络进行传输的对象。虽然说任何对象都可被序列化,但只有某些对象才能被放置到某个集合类中(如NSDictionary或NSArray中)属性列表机制将对象的相关数据存储在后缀为.plist的文件中。程序重新加载时,将从.plist文件中读取数据。
沙盒
在介绍属性列表之前简要介绍一下iOS应用的沙盒机制。iOS应用程序只能在为该程序创建的文件系统中读取文件,不可以去其它地方访问,此区域被成为沙盒,所以所有的非代码文件都要保存在此。
查看应用目录
为了更加直观的理解属性列表机制,我们在MAC上创建一个工程,并生成相应的应用,在虚拟机中运行应用。由于沙盒机制的存在,我们无法直接查看应用在虚拟机上的文件目录。可以在MAC上安装Simpholers,以方便查看虚拟机中的文件目录,安装完毕之后,可以点击工程上方(下图中红色框住的)按钮,以查看应用在虚拟机中的目录
然后在弹出的下拉框中点击对应的应用名称
接下来就可以看到应用的目录结构,如下图
属性列表生成的.plist文件将放置在应用的Documents目录下
案例
应用属性如下:
@property (strong, nonatomic) IBOutletCollection(UITextField) NSArray *lineFields;
即我们为这个应用设置了一个文本框组作为其属性,
应用界面如下:
我们的目的是,运行该应用的时候,在文本框组中填入数据,一旦应用退到后台或直接从系统退出后,将文本框的内容写入到.plist文件中。下次再启动应用时,自动读取.plist文件中的内容,然后把记录的对应文本框中的内容复制给应用中的文本框
获取.plist要保存的路径,代码如下:
- (NSString *)dataFilePath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:@"data.plist"];
}
这段代码主要做了以下事情:
(1)查找Documents目录;
(2)找到之后,在该目录下添加一个数据文件data.plist;
(3)保存数据文件data.plist的完整路径
从.plist文件中读取数据,代码如下:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSString *filePath = [self dataFilePath];
NSLog(@"%@",filePath);
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
for (int i = 0; i < 4; i++) {
UITextField *theField = self.lineFields[i];
theField.text = array[i];
}
}
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(applicationWillResignActive:)
name:UIApplicationWillResignActiveNotification
object:app];
}
在viewDidLoad方法中,做以下几件事情:
(1)检查数据文件是否存在,如果不存在,就不加载它,如果存在,就用该文件的内容实例化数组
(2)将数组中的对象复制到4个文本框
(3)从属性列表中加载数据后,得到了对应用实例的引用,用该引用订阅UIApplicationWillResignActiveNotification,也就是说,当前对象把自己设置为观察者,观察它自身的行为,如果它从前台退出了,就会收到UIApplicationWillResignActiveNotification通知,接着就执行applicationWillResignActive方法中的内容。最后一个参数app指的是发布这个通知的应用,可以看出通知发出者也是它自身
将数据写入.plist文件中,代码如下:
- (void)applicationWillResignActive:(NSNotification *)notification
{
NSString *filePath = [self dataFilePath];
NSArray *array = [self.lineFields valueForKey:@"text"];
[array writeToFile:filePath atomically:YES];
}
这个方法看起来很简单,但实际上也做了很多事情。首先通过lineFields数组中每个文本框的text方法构建一个字符串数组,然后将数据的内容写入一个属性列表文件。使用属性列表保存数据。
整个属性列表的流程就介绍完了,接下来运行程序,看看结果。
结果
首次进入,应用中的文本框是空白的,Documents文件夹下也没有文件
在每个文本框中输入一些内容,如下:
然后按shift+command+H,唤出虚拟机的主界面,这时,查看应用程序Documents文件夹,如下:
可以看到,Documents文件夹下已经生成了data.plist文件
我们可以打开该文件,查看其文件内容,如下图:
可以看到,该文件中的value的值就是我们在文本框中输入的值。我们还可以直接在这个文件上编辑,保存之后,应用重新加载时,就会直接从这个文件中读取数据,然后显示在应用中。
实际上,.plist的文件格式是xml的,用Notepad++打开data.plist文件看到的内容如下:
总结
通过对属性列表理论的理解和实际的操作,对属性列表的机制有了一定理解。实际上我觉得属性列表就是将对象的属性写入到文件中,其本质就是将数据存储在文件中。应用从前台退出时,将数据写入到属性列表文件中,应用重新运行时,又充属性列表文件中读取数据。需要注意的是,并不是任何属性都能够写入到属性列表中。如果对象包含了一个自定义的对象作为其属性,这个自定义的对象属性将无法进行序列化。可以被序列化的OC类有如下几种:
NSArray、NSMutableArry、NSDictionary、NSMutableDictionay、NSData、NSMutableData、NSString、NSMutableString、NSNumber、NSDate。
从data.plist文件的添加操作中,可以看到添加的属性种类如下:
我们大概可以理解为,属性列表中保存的数据是oc中内置的属性,这种数据持久化机制适合保存配置文件等数据内容不多的文件。