Runtime之动态获取属性列表

前一段时间使用Runtime 觉得非常有意思,一直没有时间整理.
现在被问了一些Runtime的东西,所以在这里记录下.
这里用一个场景来说明Runtime的属性列表的使用:归档解档.

正常情况下你要完成一个对象(数据model)的归档解档.你要在数据model的类继承NSCoding 协议.

//  Copyright © 2017年 like学. All rights reserved.
//
#import <Foundation/Foundation.h>

@interface PersonModel : NSObject<NSCoding>

@property (nonatomic, copy) NSString * name;
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, copy) NSString * name1;
@property (nonatomic, copy) NSString * name2;
@property (nonatomic, copy) NSString * name3;

@end
----------------------------------------
//  Copyright © 2017年 like学. All rights reserved.
//
#import "PersonModel.h"

@interface PersonModel()

@property (nonatomic, copy) NSString * age1;

@end
@implementation PersonModel

// 告诉归档那些属性
-(void)encodeWithCoder:(NSCoder *)aCoder {

    [aCoder encodeObject:_name forKey:@"name"];
    [aCoder encodeInteger:_age forKey:@"age"]; 
}

// 解档属性
-(instancetype)initWithCoder:(NSCoder *)aDecoder {

    if (self = [super init]) {
        _name = [aDecoder decodeObjectForKey:@"name"];
        _age = [aDecoder decodeIntegerForKey:@"age"];
    }
    return self;
}
@end


外面对这个进行操作
- (IBAction)setButtonValue:(id)sender {
    NSLog(@"存数据 归档");
    PersonModel * p = [[PersonModel alloc]init];
    p.name = @"like";
    p.age = 12;
    // 存进去
    NSString * temp = NSTemporaryDirectory();
    // 拼接路径 文件可以随便命名
   NSString * filePath = [temp stringByAppendingString:@"like.like"];
    // 归档的是一个对象 p
    [NSKeyedArchiver archiveRootObject:p toFile:filePath];  
}

- (IBAction)getButtonValue:(id)sender {
     NSLog(@"取数据 解档");
    NSString * temp = NSTemporaryDirectory();

    // 拼接路径
    NSString * filePath = [temp stringByAppendingString:@"like.like"];

   PersonModel * p = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
    NSLog(@"%@---%ld",p.name,(long)p.age);

}

正常情况下的数据序列化是这样的.你的数据model类中每加一个属性你都要在归档解档的方法中添加对应的代码,感觉非常的繁琐.也不想这样麻烦.

想着,把数据类的属性名字和属性个数都拿到进行for循环操作不就好了.

思路是通的,问题是怎么实现.
ok.Runtime 来拯救


#import "ViewController.h"
#import "PersonModel.h"
#import <objc/runtime.h>
@interface ViewController ()

@end

@implementation ViewController


/**
 oc的序列化和反序列化(归档解档)
 runtime
 */
- (void)viewDidLoad {
    [super viewDidLoad];
    unsigned int count = 0;
    // c语言函数参数 特点 如果是基本数据类型的指针! 基本上在函数内部会改变它的值
    // class_copyIvarList(<#__unsafe_unretained Class cls#>, <#unsigned int *outCount#>)
    // 第一参数 要对应的类
    // 第二参数 要指针参数
    // 这个方法拿到对应类的属性个数 包含.m属性的个数
    // 返回值是指针 指向的是首地址 向下取值可以拿到下一个值,类似数组但是不会像数组那样越界爆炸,可以继续取值,但是是别人的东西了
    // Ivar 结构体
    // 在C语言 函数有copy new create 在堆(堆内存程序员管理,栈是系统管理的)内存开辟空间且是连续的
   Ivar * ivars =  class_copyIvarList([PersonModel class], &count);
    NSLog(@"+++==%d",count);

    Ivar  ivar = ivars[0];
    const char * name = ivar_getName(ivar);
     NSLog(@"%s--",name);

}

了解基本的原理之后就可以这样使用
原来的model数据类 的归解档

//  Copyright © 2017年 like学. All rights reserved.
//
#import "PersonModel.h"
#import <objc/runtime.h>
@interface PersonModel()

@property (nonatomic, copy) NSString * age1;

@end
@implementation PersonModel

// 告诉归档那些属性
-(void)encodeWithCoder:(NSCoder *)aCoder {

//    [aCoder encodeObject:_name forKey:@"name"];
//    [aCoder encodeInteger:_age forKey:@"age"];
//    
//    
    unsigned int count = 0;
    Ivar * ivars = class_copyIvarList([self class], &count);
    for (int i =0; i< count; i++) {
        //拿到Ivar
        Ivar ivar = ivars[i];
        const char * name = ivar_getName(ivar);
        NSString * key = [NSString stringWithUTF8String:name];
        // 归档 kvc 不要管是否 基本数据类型 取也是这个样式
        [aCoder encodeObject:[self valueForKey:key] forKey:key];
    }
    // 这个大的花括号是个栈区 要把它给手动释放掉
    free(ivars);

}

// 解档属性
-(instancetype)initWithCoder:(NSCoder *)aDecoder {

    if (self = [super init]) {
//        _name = [aDecoder decodeObjectForKey:@"name"];
//        _age = [aDecoder decodeIntegerForKey:@"age"];


        unsigned int count = 0;
        Ivar * ivars = class_copyIvarList([self class], &count);
        for (int i =0; i< count; i++) {
            //拿到Ivar
            Ivar ivar = ivars[i];
            const char * name = ivar_getName(ivar);
            NSString * key = [NSString stringWithUTF8String:name];
          // 解档
           id value = [aDecoder decodeObjectForKey:key];
            // kvc  赋值
            [self setValue:value forKey:key];
        }

         free(ivars);

    }
    return self;
}
@end

这样就可以使用了,无论你在model的数据类中加多少属性,也不用在一个一个的添加了.
并且可以写成一个工具类,放在项目中.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值