Runtime - 多属性快速归档解档

Runtime - 多属性快速归档解档

对象归档,就是把内存中对象存储到本地。(归档的实质就是将OC对象拆分为键值对的字典,然后变成二进制存入磁盘)

对象解档,就是把本地的对象读取到内存。

常规的归解档:

创建一个Model类:Student(遵循NSCoding协议,实现归解档协议方法)

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

@interface Student : NSObject<NSCoding>

@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSUInteger age;
@property (nonatomic, copy) NSString *sex;

@end

//  Student.m
#import "Student.h"

@implementation Student
//告诉系统归档哪些属性
- (void)encodeWithCoder:(NSCoder *)aCoder{
    [aCoder encodeObject:_name forKey:@"name"];
    [aCoder encodeInteger:_age forKey:@"age"];
    [aCoder encodeObject:_sex forKey:@"sex"];
}

//解档的属性
-(instancetype)initWithCoder:(NSCoder *)aDecoder{
    if (self = [super init]) {
        _name = [aDecoder decodeObjectForKey:@"name"];
        _age = [aDecoder decodeIntegerForKey:@"age"];
        _sex = [aDecoder decodeObjectForKey:@"sex"];
    }
    return self;
}


在需要归解档的地方写上归解档方法并调用

//归档方法
- (void)save{
    //创建一个用于归档的对象并赋值
    Student *s = [[Student alloc]init];
    s.name = @"haha";
    s.age = 18;
    s.sex = @"boy";
    
    //获取沙沙盒路径
    NSString *temPath = NSTemporaryDirectory();
    //创建文件路径  stringByAppendingPathComponent 不用再加“/”
    NSString *filePath = [temPath stringByAppendingPathComponent:@"student.wsy"];
    NSLog(@"filePath==%@",filePath);
    
    //归档    file:绝对路径  需要遵守NSCoding协议
    [NSKeyedArchiver archiveRootObject:s toFile:filePath];
}

//解档方法
- (void)read{
    //获取沙沙盒路径
    NSString *temPath = NSTemporaryDirectory();
    //获取要解档文件路径
    NSString *filePath = [temPath stringByAppendingPathComponent:@"student.wsy"];
    
    Student *s = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
    NSLog(@"名字:%@ 年龄:%zi 性别:%@",s.name, s.age, s.sex);
}

  调用归档方法结果:(创建了文件,对象应该也存进去了,一会解档验证)



调用解档方法结果:(取出了对象,证明归解档成功)



那么我们就可以思考一下:如果对象属性特别多的时候,在协议方法里实现属性encode和decode就会比较麻烦,需要写好多encode 和 decode

而如果利用循环的话,我们需要知道三点:属性个数、各属性名称、各具体属性

//告诉系统归档哪些属性(解档同理)
- (void)encodeWithCoder:(NSCoder *)aCoder{
    // 伪代码  1.遍历属性个数  2.获取属性名称
    for (int i = 0; i < 属性个数 ; i++) {
        [[aCoder encodeObject:属性 forKey:属性名称];]
    }
    
}

下面就可以用到Runtime了,使用Runtime需要导入#import <objc/runtime.h>

我们可以利用 Ivar  -  成员属性

//方法:class_copyIvarList(<#__unsafe_unretained Class cls#>, <#unsigned int *outCount#>)
    //两个参数:
    //__unsafe_unretained Class cls class类型
    //unsigned int *outCount 无符号自增整型指针
    //返回值为Ivar * 类型 是个指向ivar列表地址的指针 (可以通过KVC进行修改了,小心私有API)
//示例
    unsigned int count = 0;
    Ivar * ivars = class_copyIvarList(NSClassFromString(@"Student"), &count);
    //count实质就是属性的个数(甚至放在.m里的私有属性一样能够统计进去)
    NSLog(@"count==%u",count);
    
    //ivars 是属性列表指针 通过++可以往下逐一获取到ivar,当然注意边界,越界不会崩溃,越界之后如果拿到垃圾信息就会报错
    Ivar ivar = ivars[0];
    //通过ivar_getName 可以获取到名字(返回值为c语言字符串)
    const char *name = ivar_getName(ivar);
    NSLog(@"%s",name);

打印结果:(我的Student里确实有三个属性,且.m里米有私有属性   第0个位置的确实是name属性)



OK,那么我们就可以愉快的使用了,所以model类的.m文件就变成了这样:

//  Student.m
#import "Student.h"
#import <objc/runtime.h>

@implementation Student
//告诉系统归档哪些属性
- (void)encodeWithCoder:(NSCoder *)aCoder{
    //属性个数
    unsigned int count = 0;
    Ivar * ivars = class_copyIvarList([Student class], &count);
    
    for (int i = 0; i < count; i++) {
        //拿到属性
        Ivar ivar = ivars[i];
        //拿到名称
        const char *name = ivar_getName(ivar);
        //转换成OC字符串
        NSString *key = [NSString stringWithUTF8String:name];
        [aCoder encodeObject:[self valueForKey:key] forKey:key];
    }
    //C语言里由Creat Copy创造的指针需要手动释放 ARC只管OC对象
    free(ivars);
    
}

//解档的属性
-(instancetype)initWithCoder:(NSCoder *)aDecoder{
    if (self = [super init]) {
        //属性个数
        unsigned int count = 0;
        Ivar * ivars = class_copyIvarList([Student class], &count);
        
        for (int i = 0; i < count; i++) {
            //拿到属性
            Ivar ivar = ivars[i];
            //拿到名称
            const char *name = ivar_getName(ivar);
            //转换成OC字符串
            NSString *key = [NSString stringWithUTF8String:name];
            //解档
            id value = [aDecoder decodeObjectForKey:key];
            //设置到属性上
            [self setValue:value forKey:key];
        }
        //C语言里由Creat Copy创造的指针需要手动释放 ARC只管OC对象
        free(ivars);
    }
    return self;
}

OK,这里写完就可以愉快的进行归解档了,属性再多也不怕了!











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值