在iOS学习过程中,有时候需要保持用户数据,比如登录信息、用户的设置选项等,这时候就需要学习数据持久化操作,本节主要学习iOS数据持久化相关的知识。
数据持久化的方式有四种:
1).写入plist文件(属性列表)
2).偏好设置
3).归档(NSKeyedArchiver)
4).NSData
下面分别举例说明四种方式的适用场合以及用法。
1. 写入plist文件(属性列表)
1.1 plist可以存储哪些数据
属性列表是一种XML格式的文件,拓展名为plist
如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,就可以使用writeToFile:atomically:方法直接将对象写到属性列表文件中。
由于plist文件的root只有Array和Dictionary两种类型,所以最好只保持它们对应数据类型的数据。
比如当你存储字符串类型的数据的时候,Type就为空了。
1.2 如何存储
#pragma mark - 存储数据 - (IBAction)btnSaveData_Click:(UIButton *)sender { NSString *str = @"hello"; NSString *filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"test_str.plist"]; BOOL result = [str writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil]; if (result) { NSLog(@"存储数据成功"); } else { NSLog(@"存储数据失败!"); } }
自动生成的文件:
注意:plist不能存储自定义对象类型!
<span style="color:#000000;">#pragma mark - 存储数据 - (IBAction)btnSaveData_Click:(UIButton *)sender { // 文件的沙河路径 NSString *filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"test_obj.plist"]; // 创建Student对象 CYStudent *stu = [[CYStudent alloc]init]; stu.name = @"zhangsan"; stu.age = 18; NSArray *arrTmp = @[stu]; BOOL result = [arrTmp writeToFile:filePath atomically:YES]; if (result) { NSLog(@"存储数据成功"); } else { NSLog(@"存储数据失败!"); } }</span>程序运行结果如下:
2. 偏好设置
2.1 使用场景
很多iOS应用都支持偏好设置,比如保存用户名、密码、字体大小等设置,iOS提供了一套标准的解决方案来为应用加入偏好设置功能
每个应用都有个NSUserDefaults实例,通过它来存取偏好设置。比如,保存用户名、字体大小、是否自动登录。
2.2 如何使用
登录成功后保存数据:
[[NSUserDefaults standardUserDefaults]setObject:self.txtAccount.text forKey:@"account"]; [[NSUserDefaults standardUserDefaults]setObject:self.txtPWD.text forKey:@"pwd"]; [[NSUserDefaults standardUserDefaults]setBool:self.swchRememberPWD.on forKey:@"isRememberPWD"]; [[NSUserDefaults standardUserDefaults]setBool:self.swchAutoLogin.on forKey:@"isAutoLogin"];
self.txtAccount.text = [[NSUserDefaults standardUserDefaults]objectForKey:@"account"]; self.swchAutoLogin.on = [[NSUserDefaults standardUserDefaults]boolForKey:@"isAutoLogin"]; self.swchRememberPWD.on = [[NSUserDefaults standardUserDefaults]boolForKey:@"isRememberPWD"]; self.txtPWD.text = [[NSUserDefaults standardUserDefaults]objectForKey:@"pwd"];
[defaults synchornize];
@interface CYContact : NSObject /** 姓名 */ @property (nonatomic,copy) NSString *name; /** 电话 */ @property (nonatomic,copy) NSString *phone; @end
#pragma mark - NSCoding协议方法 /* Encodes the receiverusing a given archiver 通过一个给定的archiver把消息接收者进行编码。 当接收到encodeObject消息的时候,类终端encodeWithCoder方法被调用。 */ - (void)encodeWithCoder:(NSCoder *)aCoder { [aCoder encodeObject:_name forKey:CYNameKey]; [aCoder encodeObject:_phone forKey:CYPhoneKey]; } /* Returns an objectinitialized from data in a given unarchiver. (required) 从一个给定unarchiver的数据中返回一个初始化对象。 */ - (id)initWithCoder:(NSCoder *)aDecoder { if (self = [super init]) { _name = [aDecoder decodeObjectForKey:CYNameKey]; _phone = [aDecoder decodeObjectForKey:CYPhoneKey]; } return self; } /* Returnsa new instance that’s a copy of the receiver 返回消息接收者的一个复制的新实例。 */ - (id)copyWithZone:(NSZone *)zone { CYContact *copy = [[[self class] allocWithZone:zone] init]; copy.name = [self.name copyWithZone:zone]; copy.phone = self.phone; return copy; }
[NSKeyedArchiver archiveRootObject:self.contacts toFile:CYFilePath];
self.contacts = [NSKeyedUnarchiver unarchiveObjectWithFile:CYFilePath];
4. NSData
4.1 使用场合
使用archiveRootObject:toFile:方法可以将一个对象直接写入到一个文件中,但有时候可能想将多个对象写入到同一个文件中,那么 就要使用NSData来进行归档对象
NSData可以为一些数据提供临时存储空间,以便随后写入文件,或者存放从磁盘读取的文件内容。可以使用[NSMutableData data]创建 可变数据空间
注:黑色箭头表示将对象归档到文件中,红色箭头表示从文件中恢复对象
4.2 如何使用
#pragma mark - 存储数据 - (IBAction)btnSaveData_Click:(UIButton *)sender { // NSData-归档2个Person对象到同一文件中 // 实例化对象 CYStudent *stu1 = [CYStudent studentWithName:@"zhangsan" age:18]; CYStudent *stu2 = [CYStudent studentWithName:@"lisi" age:20]; // 新建一块可变数据区 NSMutableData *data = [NSMutableData data]; // 将数据区连接到一个NSKeyedArchiver对象 NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; // 开始存档对象,存档的数据都会存储到NSMutableData中 [archiver encodeObject:stu1 forKey:@"stu1"]; [archiver encodeObject:stu2 forKey:@"stu2"]; // 存档完毕(一定要调用这个方法) [archiver finishEncoding]; NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"datas.data"]; // 将存档的数据写入文件 BOOL result = [data writeToFile:path atomically:YES]; if (result) { NSLog(@"存储数据成功"); } else { NSLog(@"存储数据失败!"); } } #pragma mark - 读取数据 - (IBAction)btnReadData_Click:(UIButton *)sender { // NSData-从同一文件中恢复2个Person对象 // 从文件中读取数据 NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"datas.data"]; NSData *data = [NSData dataWithContentsOfFile:path]; // 根据数据,解析成一个NSKeyedUnarchiver对象 NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; CYStudent *stu1 = [unarchiver decodeObjectForKey:@"stu1"]; CYStudent *stu2 = [unarchiver decodeObjectForKey:@"stu2"]; // 恢复完毕 [unarchiver finishDecoding]; NSLog(@"%@",stu1); NSLog(@"%@",stu2); } #pragma mark - 利用归档实现深复制 - (IBAction)btnDeepCopy_Click:(UIButton *)sender { // 比如对一个CYStudent对象进行深复制 // 临时存储stu1的数据 CYStudent *stu1 = [CYStudent studentWithName:@"zhangsan" age:18]; NSData *data = [NSKeyedArchiver archivedDataWithRootObject:stu1]; // 解析data,生成一个新的Person对象 CYStudent *stu2 = [NSKeyedUnarchiver unarchiveObjectWithData:data]; // 分别打印内存地址 NSLog(@"stu1:%p", stu1); // stu1:0x7bdb32b0 NSLog(@"stu2:%p", stu2); // stu2:0x7bdb6b80 }