数据存储之Archiver、Unarchiver、偏好设置
- 数组的归档
- 对象的归档
- NSData多个对象的归档
- NSArray多个对象的归档
- 偏好设置的存储
1.NSString、NSDictionary、NSArray、NSData、NSNumber等类型的对象,可以直接用NSKeyedArchiver进行归档和恢复
2.不是所有的对象都可以直接用这种方法进行归档,只有遵守了NSCoding协议的对象才可以
1⃣️归档和恢复
支持复杂的数据对象,包括自定义对象。
对自定义对象进行归档处理,需要实现NSCoding协议
2⃣️NSCoding协议方法
encodeWithCoder
initWithCoder
3⃣️NSKeyedArchiver & NSKeyedUnarchiver
4⃣️对于多个对象可以通过NSArray或者NSData进行归档
一、数组的归档
// 演练1 NSArray归档 // 注意,可以通过修改文件名查看归档文件内容 NSString *path = [docDir stringByAppendingPathComponent:@"array.archive"]; // 定义数组 NSArray *array = @[@"张三", @"李四", @"王五"]; // 归档数组 [NSKeyedArchiver archiveRootObject:array toFile:path]; // 恢复数组 NSArray *unarchivedArray = [NSKeyedUnarchiver unarchiveObjectWithFile:path]; NSLog(@"%@", unarchivedArray);
二、对象的归档
1⃣️重写NSCoding两个方法
// 归档 - (void)encodeWithCoder:(NSCoder *)aCoder { [aCoder encodeObject:_name forKey:@"name"]; // 图像数据 NSData *imageData = UIImagePNGRepresentation(_userImage); [aCoder encodeObject:imageData forKey:@"imageData"]; [aCoder encodeInt:_age forKey:@"age"]; [aCoder encodeObject:_phone forKey:@"phone"]; } // 恢复 - (id)initWithCoder:(NSCoder *)aDecoder { [self setName:[aDecoder decodeObjectForKey:@"name"]]; // 图像数据 NSData *imageData = [aDecoder decodeObjectForKey:@"imageData"]; [self setUserImage:[UIImage imageWithData:imageData]]; [self setAge:[aDecoder decodeIntForKey:@"age"]]; [self setPhone:[aDecoder decodeObjectForKey:@"phone"]]; return self; }
2⃣️归档和恢复
// 归档文件路径 NSArray *documents = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *path = [documents[0]stringByAppendingPathComponent:@"personInfo.plist"]; // 新建Person对象 Person *person = [Person initPersonWithName:_userNameText.text image:_userImageView.image age:_ageText.text.intValue phone:_phoneText.text]; // 归档用户数据 [NSKeyedArchiver archiveRootObject:person toFile:path];
// 恢复文件路径 NSArray *documents = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *path = [documents[0]stringByAppendingPathComponent:@"personInfo.plist"]; // 恢复Person对象 Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:path]; [_userNameText setText:person.name]; [_userImageView setImage:person.userImage]; [_ageText setText:[NSString stringWithFormat:@"%d", person.age]]; [_phoneText setText:person.phone];
三、NSData多个对象的归档(用于不同对象)
1⃣️归档
// 演练3. 归档多个对象 - (void)archivedMultiObjects { // 获取文档目录 NSArray *documents = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); // 存档路径 NSString *path = [documents[0]stringByAppendingPathComponent:@"multiUsers.plist"]; Person *person1 = [Person initPersonWithName:@"张三" image:[UIImage imageNamed:@"头像1.png"] age:18 phone:@"110"]; Person *person2 = [Person initPersonWithName:@"李四" image:[UIImage imageNamed:@"头像2.png"] age:32 phone:@"120"]; // 新建一块可变的数据区 NSMutableData *data = [NSMutableData data]; // 将数据区连接到一个NSKeyedArchiver对象 NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:data]; // 开始存档对象,存档的数据都会存储到NSMutableData中 [archiver encodeObject:person1 forKey:@"person1"]; [archiver encodeObject:person2 forKey:@"person2"]; // 存档完毕(一定要调用这个方法) [archiver finishEncoding]; // 将存档的数据写入文件 [data writeToFile:path atomically:YES]; }
2⃣️恢复
- (void)unarchiverPersonInfo:(UIButton *)sender { // 演练3. 恢复NSData归档的多个数据 // 获取文档目录 NSArray *documents = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); // 存档路径 NSString *path = [documents[0]stringByAppendingPathComponent:@"multiUsers.plist"]; // 演练4. 使用NSArray归档多个对象 NSString *path2 = [documents[0]stringByAppendingPathComponent:@"multiUsers2.plist"]; NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithFile:path2]; for (Author *author in array) { NSLog(@"%@ %d %@ %@", author.name, author.age, author.phone, author.bookName); } // 从文件读取数据 NSData *data = [NSData dataWithContentsOfFile:path]; // 根据数据,解析成一个NSKeyedUnarchiver对象 NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc]initForReadingWithData:data]; // 恢复对象 Person *person1 = [unarchiver decodeObjectForKey:@"person1"]; Person *person2 = [unarchiver decodeObjectForKey:@"person2"]; // 恢复完毕(一定要调用这个方法) [unarchiver finishDecoding]; // 根据按钮Tag设置UI if (sender.tag == 0) { [_userNameText setText:person1.name]; [_userImageView setImage:person1.userImage]; [_ageText setText:[NSString stringWithFormat:@"%d", person1.age]]; [_phoneText setText:person1.phone]; } else { [_userNameText setText:person2.name]; [_userImageView setImage:person2.userImage]; [_ageText setText:[NSString stringWithFormat:@"%d", person2.age]]; [_phoneText setText:person2.phone]; } }
四、NSArray多个对象的归档(用于相同对象)
1⃣️写一个Author类,继承Person
类中需要重写两个方法
// 归档 - (void)encodeWithCoder:(NSCoder *)aCoder { [super encodeWithCoder:aCoder]; [aCoder encodeObject:_bookName forKey:@"bookName"]; } // 恢复 - (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { _bookName = [aDecoder decodeObjectForKey:@"bookName"]; } return self; }
2⃣️使用NSArray归档
// 演练4. 使用NSArray归档多个对象 - (void)archivedMultiObjectsWithArray; { // 获取文档目录 NSArray *documents = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); // 存档路径 NSString *path = [documents[0]stringByAppendingPathComponent:@"multiUsers2.plist"]; Author *author1 = [Author initPersonWithName:@"张大师" image:[UIImage imageNamed:@"头像1.png"] age:30 phone:@"110" bookName:@"C语言基础"]; Author *author2 = [Author initPersonWithName:@"张大师" image:[UIImage imageNamed:@"头像1.png"] age:30 phone:@"110" bookName:@"C++宝典"]; NSArray *array = @[author1, author2]; // 注意此处不能使用 [array writeToFile:path atomically:YES]; [NSKeyedArchiver archiveRootObject:array toFile:path]; }
3⃣️解档
NSArray *documents = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); // 存档路径 NSString *path = [documents[0]stringByAppendingPathComponent:@"multiUsers.plist"]; // 演练4. 使用NSArray归档多个对象 NSString *path2 = [documents[0]stringByAppendingPathComponent:@"multiUsers2.plist"]; NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithFile:path2]; for (Author *author in array) { NSLog(@"%@ %d %@ %@", author.name, author.age, author.phone, author.bookName); }
五、偏好设置的存储
注意:UserDefaults设置数据时,不是立即写入,而是根据时间戳定时地把缓存中的数据写入本地磁盘。所以调用了set方法之后数据有可能还没有写入磁盘,应用程序就终止了。
出现以上问题,可以通过调用synchornize方法强制写入:
[defaults synchronize];
1⃣️偏好设置保存
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setObject:@"王二麻子" forKey:@"UserName"]; [defaults setFloat:18.5 forKey:@"fontSize"]; [defaults setBool:NO forKey:@"purchased"]; [[NSUserDefaults standardUserDefaults]setObject:@"110" forKey:@"Phone"]; // 同步命令 [[NSUserDefaults standardUserDefaults]synchronize];
2⃣️取出
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSString *userName = [defaults objectForKey:@"userName"]; float fontSize = [defaults floatForKey:@"fontSize"]; BOOL autoLogin = [defaults boolForKey:@"autoLogin"];