这篇文章主要写NSKeyArchiver归档和NSKeyUnarchiver解档的实现
最终存储后的效果图为:
Demo地址
对应的文件是Human.m和ArchiveViewController.m
目的是希望能归档解档自定义对象,需要遵守NSSecureCoding协议,这部分在上一篇iOS开发中数据持久化(二):NSUserDefault实现数据存储
里面讲过,所以human.m的实现和上一篇中person.m的实现类似,这里直接写代码
在human.h中,声明相应的属性
@interface Human : NSObject<NSSecureCoding>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;
@end
在human.m文件中,实现相应的协议方法
+ (BOOL)supportsSecureCoding {
return YES;
}
//1.编码方法
- (void)encodeWithCoder:(nonnull NSCoder *)coder {
[coder encodeObject:self.name forKey:@"HumanName"];
[coder encodeInteger:self.age forKey:@"HumanAge"];
}
//2.解码方法
- (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder {
self = [super init];
if (self) {
self.name = [coder decodeObjectForKey:@"HumanName"];
self.age = [coder decodeIntegerForKey:@"HumanAge"];
}
return self;
}
之后,创建ArchiveViewController,继承自UIViewController,主要有两种归档、解档方法(勉强可以算是两种),我们希望将数据存储到两个不同的文件中
上面的效果图中data1文件存储的是第一种方法归档后的数据
data2文件存储的是第二种方法归档后的数据
所以声明两个路径以及归档按钮、解档按钮
在ArchiveViewController.h中
声明相应的属性
@property (nonatomic, strong) UIButton *archiveButton;
@property (nonatomic, strong) UIButton *unarchiveButton;
@property (nonatomic, copy) NSString *path1;
@property (nonatomic, copy) NSString *path2;
在.m文件中,懒加载以及完成基本的布局
//放置在Cache文件夹下
- (NSString *)path1 {
if (_path1) {
return _path1;
}
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
_path1 = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"Data1"];
NSLog(@"path1 = %@",_path1);
return _path1;
}
//放置在cache文件夹下
- (NSString *)path2 {
if (_path2) {
return _path2;
}
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
_path2 = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"Data2"];
NSLog(@"path2 = %@",_path2);
return _path2;
}
- (UIButton *)archiveButton {
if (_archiveButton) {
return _archiveButton;
}
_archiveButton = [[UIButton alloc] initWithFrame:CGRectZero];
_archiveButton.titleLabel.font = [UIFont systemFontOfSize:18];
[_archiveButton setTitle:@"归档" forState:UIControlStateNormal];
[_archiveButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_archiveButton addTarget:self action:@selector(archiveData) forControlEvents:UIControlEventTouchUpInside];
return _archiveButton;
}
- (UIButton *)unarchiveButton {
if (_unarchiveButton) {
return _unarchiveButton;
}
_unarchiveButton = [[UIButton alloc] initWithFrame:CGRectZero];
_unarchiveButton.titleLabel.font = [UIFont systemFontOfSize:18];
[_unarchiveButton setTitle:@"解档" forState:UIControlStateNormal];
[_unarchiveButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_unarchiveButton addTarget:self action:@selector(unarchiveData) forControlEvents:UIControlEventTouchUpInside];
return _unarchiveButton;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.navigationController.navigationBar.translucent = NO;
self.title = @"归档解档实现";
self.view.backgroundColor = [UIColor whiteColor];
[self.view addSubview:self.archiveButton];
[self.archiveButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.view);
make.centerY.equalTo(self.view);
make.width.greaterThanOrEqualTo(@0);
make.height.equalTo(@30);
}];
[self.view addSubview:self.unarchiveButton];
[self.unarchiveButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.view);
make.top.equalTo(self.archiveButton.mas_bottom).offset(20);
make.width.greaterThanOrEqualTo(@0);
make.height.equalTo(@30);
}];
}
下面就是归档、解档的具体实现,在archiveData()方法中实现归档,在unarchiveData()方法中实现解档
这部分也是花费时间最多的部分,因为我设备是ios14,看原先的博客都是使用archiveRootObject...tofile就可将对象归档到文件中
但是在iOS14中,这个方法已经被弃用了
后面只能看苹果开发文档
发现可以算做两种方法实现归档、解档
(本质都是一样的,获取到归档后的NSData数据,然后将其写入相应的文件中)
一种是使用类方法实现
一种是使用实例方法实现,可以添加对应的键值
类方法实现归档解档
这个归档的路径使用path1
归档相关的代码为:
- (void)archiveData {
Human *human = [[Human alloc] init];
human.name = @"落叶兮兮";
human.age = 24;
//第一种方法,使用NSKeyArchiver类方法,将对象转化为NSData,然后写入指定的文件中
NSError *error = nil;
NSData *data1 = [NSKeyedArchiver archivedDataWithRootObject:human requiringSecureCoding:YES error:&error];
if (error) {
NSLog(@"归档失败,失败的原因是%@",error);
}
BOOL success = [data1 writeToFile:self.path1 atomically:YES];
if (success) {
NSLog(@"写入成功");
} else {
NSLog(@"写入失败");
}
}
运行后,点击归档,就可以看到相应的文件存在
对应的解档读取数据的代码如下:
- (void)unarchiveData {
NSLog(@"开始解档数据");
//使用NSKeyedUnarchiver类方法解析
NSData *data1 = [NSData dataWithContentsOfFile:self.path1];
NSError *error1 = nil;
Human *human1 = [NSKeyedUnarchiver unarchivedObjectOfClass:[Human class] fromData:data1 error:&error1];
if (error1) {
NSLog(@"解档数据失败,失败的原因是%@",error1);
} else {
NSLog(@"解档数据成功");
NSLog(@"human name = %@,age = %ld",human1.name,human1.age);
}
}
运行成功,点击解档,可以读取相应的内容
使用实例方法归档和解档
这个归档的路径使用path2
归档的代码为:
- (void)archiveData {
NSLog(@"开始归档数据");
Human *human = [[Human alloc] init];
human.name = @"落叶兮兮";
human.age = 24;
//第二种使用NSKeyArchiver的实例方法,编码时使用相应的键值,然后将编码后的数据写入执行的路径中
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
[archiver encodeObject:human forKey:@"Human"];
[archiver finishEncoding];
NSLog(@"NSKeyArchiver编码的数据为%@",archiver.encodedData);
[archiver.encodedData writeToFile:self.path2 atomically:YES];
NSLog(@"归档结束");
}
解档的代码为:(注意解档时的键值要和归档的键值保持一致)
//使用NSKeyedUnarchiver实例方法解析
NSError *error2 = nil;
NSData *data2 = [NSData dataWithContentsOfFile:self.path2];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:data2 error:&error2];
Human *human2 = [unarchiver decodeObjectOfClass:[Human class] forKey:@"Human"];
[unarchiver finishDecoding];
if (error2) {
NSLog(@"解档数据失败,失败的原因是%@",error2);
} else {
NSLog(@"解档数据成功");
NSLog(@"human name = %@,age = %ld",human2.name,human2.age);
}
运行后,可以查看到相应的文件
而且,来年各种功能方法存储的是一样的内容,data1文件的大小是243kb,data2文件的大小是244kb,或许就是因为data2存储时设置了键值“Human”
总结
最终存储后的效果图为:
Demo地址
对应的文件是Human.m和ArchiveViewController.m
iOS开发中数据持久化总结(一);
iOS开发中数据持久化总结(二):NSUserDefault实现数据存储
ios开发中数据持久化总结(三):NSKeyArchive归档解档的实现
ios开发中数据持久化总结(四):使用FMDataBase存储数据