iOS开发中数据持久化(三):NSKeyArchive归档解档的实现

这篇文章主要写NSKeyArchiver归档和NSKeyUnarchiver解档的实现

最终存储后的效果图为:


image.png

Demo地址
对应的文件是Human.m和ArchiveViewController.m

目的是希望能归档解档自定义对象,需要遵守NSSecureCoding协议,这部分在上一篇iOS开发中数据持久化(二):NSUserDefault实现数据存储

里面讲过,所以human.m的实现和上一篇中person.m的实现类似,这里直接写代码
在human.h中,声明相应的属性

@interface Human : NSObject

@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(@"写入失败");
    }
}

运行后,点击归档,就可以看到相应的文件存在


image.png

对应的解档读取数据的代码如下:

- (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);
    }

运行后,可以查看到相应的文件


image.png

而且,来年各种功能方法存储的是一样的内容,data1文件的大小是243kb,data2文件的大小是244kb,或许就是因为data2存储时设置了键值“Human”

总结

最终存储后的效果图为:


image.png

Demo地址
对应的文件是Human.m和ArchiveViewController.m

iOS开发中数据持久化总结(一);
iOS开发中数据持久化总结(二):NSUserDefault实现数据存储
ios开发中数据持久化总结(三):NSKeyArchive归档解档的实现
ios开发中数据持久化总结(四):使用FMDataBase存储数据

你可能感兴趣的:(iOS开发中数据持久化(三):NSKeyArchive归档解档的实现)