何谓数据持久化?
能将内催中的数据类型转换为存储模型,并能在将来需要时将存储模型还原为数据模型的机制。通俗讲就是将数据包存在非一时性设备中,并能在需要的时候恢复,苹果也就是从内存到闪存的过程。
NSUserDefaults
用NSUserDefaults存储配置信息
NSUserDefaults本质是以Key-Value形式存在plist文件,放在App的Library/Preferences目录下。这个文件是不安全的,所以千万不要用NSUserDefaults来存储密码之类的敏感消息,用户名密码应该使用KeyChain来存储
。
NSUserDefaults被设计用来存储设备和应用的配置信息,它通过一个工厂方法返回默认的、也是最常用到的实例对象。这个对象中储存了系统中用户的配置信息,开发者可以通过这个实例对象对这些已有的信息进行修改,也可以按照自己的需求创建新的配置项。
/**
1. 该单例对象封装了对plist文件的读写操作,可以对每个字段单独读写
2. 该plist文件在系统的Library/Preferences目录下,名字为<<Bundle Identify.plist>>
*/
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
// 2. 写操作
// 将开关的值记录到plist文件中,键为"switch"
[defaults setBool:_toggle.on forKey:@"switch"];
// 将进度值文本框的内容记录到plist文件中,键为"progress"
NSString *progress = _progressTextField.text;
float progressValue = [progress floatValue];
[defaults setFloat:progressValue forKey:@"progress"];
// 将输入文本框的内容记录到plist文件中,键位"input"
[defaults setObject:_inputTextField.text forKey:@"input"];
// 3. 将内存中的配置值,刷新到plist文件中
[defaults synchronize];
NSUserDefaults把配置信息以字典的形式组织起来,支持字典的项包括:字符串或者是数组,除此之外还支持数字等基本格式。一句话概括就是:基础类型的小数据的字典。操作方法几乎与NSDictionary的操作方法无异,另外还可以通过指定返回类型的方法获取到指定类型的返回值。
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
_toggle.on = [defaults boolForKey:@"switch"];
_progressView.progress = [defaults floatForKey:@"progress"];
_label.text = [defaults stringForKey:@"input"];
SQLite
iOS的SDK里预置了SQLite的库,开发者可以自建SQLite数据库。SQLite每次写入数据都会产生IO消耗,把数据归档到相应的文件。
SQLite擅长处理的数据类型其实与NSUserDefaults差不多,也是基础类型的小数据,只是从组织形式上不同。开发者可以以关系型数据库的方式组织数据,使用SQL DML来管理数据。 一般来说应用中的格式化的文本类数据可以存放在数据库中,尤其是类似聊天记录、Timeline等这些具有条件查询和排序需求的数据。
每一个数据库的句柄都会在内存中都会被分配一段缓存,用于提高查询效率。另一个方面,由于查询缓存,当产生大量句柄或数据量较大时,会出现缓存过大,造成内存浪费。
SQLite的使用起来要比NSUserDefaults复杂的多,因此建议开发者使用SQLite要搭配一个操作控件使用,可以简化操作。
NSCoding+NSKeyedArchiver
1.NSCoding协议
// 解档 反序列化 解码 从data(file)->对象
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super init]) {
_name = [aDecoder decodeObjectForKey:kNameKey];
_age = [aDecoder decodeIntForKey:kAgeKey];
_identify = [aDecoder decodeObjectForKey:kIdKey];
}
return self;
}
// 归档 序列化 编码 从对象->data(file)
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:_name forKey:kNameKey];
[aCoder encodeInt:_age forKey:kAgeKey];
[aCoder encodeObject:_identify forKey:kIdKey];
}
2.保存数据
SFStudent *student = [[SFStudent alloc] init];
student.name = _name.text;
student.age = [_age.text intValue];
student.identify = _identify.text;
// 将student对象归档到文件
[NSKeyedArchiver archiveRootObject:student toFile:_path];
3.读取数据
// 解档出一个对象
SFStudent *student = [NSKeyedUnarchiver unarchiveObjectWithFile:_path];
if (student == nil) {
return;
}
_name.text = student.name;
_age.text = [@(student.age) stringValue];
_identify.text = student.identify;