首页 > 代码库 > iOS学习笔记-数据持久化
iOS学习笔记-数据持久化
在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>程序运行结果如下:
1.3 plist文件的存储与读取过程
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"];
注意:UserDefaults设置数据时,不是立即写入,而是根据时间戳定时地把缓存中的数据写入本地磁盘。所以调用了set方法之后数据有可能还没有写入磁盘应用程序就终止了。出现以上问题,可以通过调用synchornize方法强制写入
[defaults synchornize];
3. 归档(NSKeyedArchiver)
3.1 使用场合
如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,可以直接用NSKeyedArchiver进行归档和恢复
不是所有的对象都可以直接用这种方法进行归档,只有遵守了NSCoding协议的对象才可以
NSCoding协议有2个方法:
1)encodeWithCoder:
每次归档对象时,都会调用这个方法。一般在这个方法里面指定如何归档对象中的每个实例变量,可以使用encodeObject:forKey:方法归档实例变量
2)initWithCoder:
每次从文件中恢复(解码)对象时,都会调用这个方法。一般在这个方法里面指定如何解码文件中的数据为对象的实例变量,可以使用decodeObject:forKey方法解码实例变量
3.2 如何使用
1> 自定义实体类
@interface CYContact : NSObject /** 姓名 */ @property (nonatomic,copy) NSString *name; /** 电话 */ @property (nonatomic,copy) NSString *phone; @end
2> 实现NSCoding协议方法
#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; }
3> 归档
[NSKeyedArchiver archiveRootObject:self.contacts toFile:CYFilePath];
4> 接档
self.contacts = [NSKeyedUnarchiver unarchiveObjectWithFile:CYFilePath];
5> 注意点
如果父类也遵守了NSCoding协议,请注意:
? 应该在encodeWithCoder:方法中加上一句[super encodeWithCode:encode];确保继承的实例变量也能被编码,即也能被归档
? 应该在initWithCoder:方法中加上一句self = [super initWithCoder:decoder];确保继承的实例变量也能被解码,即也能被恢复
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 }
iOS学习笔记-数据持久化