iOS归档和解档

关键词:

  • 归档:数据持久化的一种方式,是将数据进行编码序列化之后存储的过程。适用于小量数据的存储。

  • 解档:对归档的数据进行解码,拿到当初归档的数据的过程。

  • NSCoding:A protocol that enables an object to be encoded and decoded for archiving and distribution.
    一种能够对对象进行编码和解码,以实现归档和解档案的协议,也就是说只有遵循了NSCoding这个协议才能实现数据的归档和解档。
    NSCoding 是一个简单的协议,通过 -initWithCoder: 和 encodeWithCoder:方法,遵循NSCoding协议的类可以被序列化和反序列化,这样可以将数据归档到磁盘上。

沙盒、Archiver 、encode、UnArchiver、decode、、NSCoder、NSKeyedArchiver、NSKeyedUnarchiver、NSKeyedArchiverDelegate、NSKeyedUnarchiverDelegate

归档的缺点:归档的形式来保存数据,只能一次性归档保存以及一次性解压。所以只能针对小量数据,而且对数据操作比较笨拙,即如果想改动数据的某一小部分,还是需要解压整个数据或者归档整个数据

实现过程

1、归档和解档一个对象

ViewController

ViewController.m

#import "ViewController.h"
#import "Person.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    
    Person *person = [[Person alloc]init];
    person.name = @"小明";
    person.age = 23;
    person.gender = GenderMan;
    person.isAdult = YES;
    person.labelArray = @[@"阳光",@"萌新",@"正太"];
    person.car.color = [UIColor blackColor];
    
    // 归档Person对象
    [NSKeyedArchiver archiveRootObject:person toFile:[Person archivePath]];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
    // 解档Person属性,并打印
    Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:[Person archivePath]];
    NSLog(@"%@",person.name);
    NSLog(@"%ld",person.age);
    NSLog(@"%ld",person.gender);
    NSLog(@"%d",person.isAdult);
    NSLog(@"%@",person.labelArray);
    NSLog(@"%@",person.car.color);
}
  • 为了方便测试,我们直接在viewDidLoad创建了一个person对象,并给其属性赋了值,之后将person这个对象进行了归档。
  • 在touch方法里面我们解档了person对象,然后将归档的属性值打印了出来。
  • 这里需要注意一下,项目中根据情况,有时候归档和解档需要异步处理,自己添加子线程即可。

这个过程就实现了对一个对象的归档和解档,那么在Person类里面操作如下:

Person

Person.h

#import <Foundation/Foundation.h>
#import "Car.h"

typedef NS_ENUM(NSInteger,Gender){
    GenderMan=1,
    GenderWoman
};

@interface Person : NSObject<NSCoding>//归档解档需要遵守NSCopying协议

@property (nonatomic, copy  ) NSString   *name;//姓名
@property (nonatomic        ) Gender     gender;//性别
@property (nonatomic        ) NSUInteger age;//年龄
@property (nonatomic        ) BOOL       isAdult;//是否成年
@property (nonatomic, strong) NSArray    *labelArray;//性格标签数组

@property (nonatomic, strong) Car        *car;

// 归档地址
+ (NSString *)archivePath;

@end

Person.m

#import "Person.h"

@implementation Person

- (void)encodeWithCoder:(NSCoder *)aCoder {
    // 归档
    // 这里的Key为了方便和减少错误,最好就用属性作为Key
    // 不同类型的属性有不同的归档和解档方法

    [aCoder encodeObject:self.name forKey:@"name"];
    [aCoder encodeInteger:self.gender forKey:@"gender"];
    [aCoder encodeInteger:self.age forKey:@"age"];
    [aCoder encodeBool:self.isAdult forKey:@"isAdult"];
    [aCoder encodeObject:self.labelArray forKey:@"labelArray"];
    // 这里注意一下,归档一个对象的时候,这个对象也需要实现NSCoding协议和相应的方法,不然的话直接闪退,闪退日志如下:
    // -[Car encodeWithCoder:]: unrecognized selector sent to instance
    [aCoder encodeObject:self.car forKey:@"car"];
}

- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super init]) {
        // 解档,赋值
        // 这里的Key需与归档时的Key一致
        
        self.name = [aDecoder decodeObjectForKey:@"name"];
        self.gender = [aDecoder decodeIntegerForKey:@"gender"];
        self.age = [aDecoder decodeIntegerForKey:@"age"];
        self.isAdult = [aDecoder decodeBoolForKey:@"isAdult"];
        self.labelArray = [aDecoder decodeObjectForKey:@"labelArray"];
        self.car = [aDecoder decodeObjectForKey:@"car"];
    }
    return self;
}

// 归档地址
+ (NSString *)archivePath {
    NSString *path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
    return [path stringByAppendingString:@"PersonCache"];
}

//通过get方法创建car对象,外部不再需要每次创建,直接使用点语法给car的属性赋值即可。
- (Car *)car {
    if (!_car) {
        _car = [[Car alloc]init];
    }
    return _car;
}
@end
  • 这里的Person和Car是我们创建的两个类,算是两个Model。
  • Person中有一些属性,特别的它有一个属性car。
  • 归档需要 有一个归档的地址,我们直接用类方法返回一个归档路径。

Car

Car.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface Car : NSObject<NSCoding>//Car也需要遵循NSCoding协议

@property (nonatomic, strong) UIColor *color;//汽车颜色

@end

Car.m

#import "Car.h"

@implementation Car

- (void)encodeWithCoder:(NSCoder *)aCoder {
    
    [aCoder encodeObject:self.color forKey:@"color"];
}

- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super init]) {
        
        self.color = [aDecoder decodeObjectForKey:@"color"];
    }
    return self;
}
@end
  • Car有一个属性color,要想归档Person对象的car属性,则需要Car也遵循NSCoding协议,而且也需要实现自己的归档和解档方法。

到这里归档和解档一个对象的操作就完成了

小结

总结一下归档一个对象需要以下几个步骤:
1、遵循NSCoding协议<NSCoding>
2、实现归档和解档的方法

  • (void)encodeWithCoder:(NSCoder *)aCoder
  • (nullable instancetype)initWithCoder:(NSCoder *)aDecoder

3、归档或者解档

// 归档Person
[NSKeyedArchiver archiveRootObject:person toFile:[Person archivePath]];
// 解档Person
Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:[Person archivePath]];

2、归档一个数组、字典等

与归档一个对象一样的原理,这里讲归档数组的地址写了一个宏。

//数组归档地址
#define kChachArrayPath [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject stringByAppendingString:@"MyArray"]
// 归档数组
NSArray *array = @[@"阳光",@"萌新",@"正太"];
[NSKeyedArchiver archiveRootObject:array toFile:kChachArrayPath];
// 解档数组
NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithFile:kChachArrayPath];
NSLog(@"%@",array[0]);

这种只归档了一个数组的方式如果在项目中使用,建议不要这样用,因为不方便管理。推荐使用NSUserDefaults。根据具体的项目情况选择最合适的。

demo

https://github.com/Mexiang/Archive

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,978评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,954评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,623评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,324评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,390评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,741评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,892评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,655评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,104评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,569评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,254评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,834评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,725评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,950评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,260评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,446评论 2 348

推荐阅读更多精彩内容