runtime实现数据模型,自动绑定数据

引言

该篇博客的思路是学习了以前看过的一篇博文,时间有点久,现在已经找不到了。算是借花献佛一把,与大家分享一下如何建立数据模型,并且实现当属性名与字典key值一致时,自动给属性赋值。

开始

还是先来讲讲思路吧。我们的目的是给模型传入数据,当模型中属性名与字典key一致时,属性的值就为字典key对应的值。要实现这点,最关键的就是如何匹配key与属性名,并且将value赋给属性。
上篇博客中,我们讲过利用runtime获取类中所有属性名,属性名获取到了,遍历字典的key,当属性名与key一致时,重写set方法,将key对应的value赋给属性,这样不就能实现了吗?

让我们开始动手实现吧

因为该数据模型不涉及UI,我们直接使用控制台新建工程。

1.创建测试使用的字典,模拟从服务器获得数据
NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithCapacity:11];
        //创建测试使用的字典
        for (int i = 0; i < 11; i ++) {

            NSString *key = [NSString stringWithFormat:@"boy%d",i];

            NSString *value = [NSString stringWithFormat:@"i am the %i boy",i];
            [data setValue:value forKey:key];
        }

        NSLog(@"%@",data);

输出结果:
2016-06-14 12:00:17.684 Runtime[10402:872011] Hello, World!
2016-06-14 12:00:17.686 Runtime[10402:872011] {
boy0 = “i am the 0 boy”;
boy1 = “i am the 1 boy”;
boy10 = “i am the 10 boy”;
boy2 = “i am the 2 boy”;
boy3 = “i am the 3 boy”;
boy4 = “i am the 4 boy”;
boy5 = “i am the 5 boy”;
boy6 = “i am the 6 boy”;
boy7 = “i am the 7 boy”;
boy8 = “i am the 8 boy”;
boy9 = “i am the 9 boy”;
}
笔者将在这个数据基础上为大家一步一步讲解如何动态绑定属性

2.创建数据模型基类BaseModel继承与NSObject
3.在.m中根据key值生成set方法和get方法
/**
 *  根据Key值生成set方法:首先要编写的方法是传入一个字符串,然后返回该字符串所对应属性的setter方法。这个方法其实很简单的,就是把对应的字符串的首字母大写并且拼接上set关键字,再生产SEL并返回
 */
- (SEL)creatSetmethodWithPropertyName:(NSString *)propertyName {

    //1.首字母大写
    propertyName = propertyName.capitalizedString;

    //2.拼接上set关键字
    propertyName = [NSString stringWithFormat:@"set%@:",propertyName];

    //返回set方法
    return NSSelectorFromString(propertyName);
}


/**
 *  通过字符串来创建该字符串的Getter方法,并返回
 */
- (SEL)creatGettermethodWithPropertyName:(NSString *)propertyName {

    return NSSelectorFromString(propertyName);
}
4.通过runtime获取当前对象的所有属性名称
/**
 *  通过运行时获取当前对象的所有属性名称,以数组的形式返回
 */
- (NSArray *)allPropertyName {

    //存储所有的属性名称
    NSMutableArray *allNames = [[NSMutableArray alloc] init];

    //存储属性的个数
    unsigned int propertyCount = 0;

    //通过运行时获取当前类的属性
    objc_property_t *propertys = class_copyPropertyList([self class], &propertyCount);

    //把属性放在数组中
    for (int i = 0; i < propertyCount; i ++) {

        //取出第一个属性
        objc_property_t property = propertys[i];
        const char *propertyName = property_getName(property);

        [allNames addObject:[NSString stringWithUTF8String:propertyName]];
    }

    //释放
    free(propertys);

    return allNames;
}
返回的allNames即为所有属性名的数组
5.给模型添加外部调用接口
- (instancetype)initWithDictionary:(NSDictionary *)dic {

    if (self = [super init]) {
       [self assginToPropertyWithDictionary:dic];
    }   
    return self;
}

+ (instancetype)modelWithDictionary:(NSDictionary *)dic {

    return [[self alloc] initWithDictionary:dic];
}
6.在assginToPropertyWithDictionary:方法中将key对应的value赋给属性
- (void)assginToPropertyWithDictionary:(NSDictionary *)dic {

    if (dic==nil) {
        return;
    }

    //1.获取dic中所有的键
    NSArray *keyAry = [dic allKeys];

    //循环遍历字典的key,并且动态生成实体类的setter方法
    for (int i = 0; i < keyAry.count; i ++) {

        //通过上面的方法获取到每个属性的set方法
        SEL setSel = [self creatSetmethodWithPropertyName:keyAry[i]];

        if ([self respondsToSelector:setSel]) {
            //获取字典中key所对应的value
            NSString *value = [NSString stringWithFormat:@"%@",dic[keyAry[i]]];

            //把值通过setter方法赋值给实体类属性
            [self performSelectorOnMainThread:setSel withObject:value waitUntilDone:[NSThread isMainThread]];
        }
    }

}
7.运行时获取方法签名,外部可调用
/**
 *  运行时获取方法签名
 */
- (void)displayCurrentModelProperty {

    //获取实体类的属性名
    NSArray *array = [self allPropertyName];

    //拼接参数
    NSMutableString *resultString = [[NSMutableString alloc] init];

    for (int i = 0; i < array.count; i ++) {

        //获取get方法
        SEL getSel = [self creatGettermethodWithPropertyName:array[i]];

        if ([self respondsToSelector:getSel]) {
            //获取类和方法的签名
            NSMethodSignature *signature = [self methodSignatureForSelector:getSel];

            //从签名获得调用对象
            NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];

            //设置target
            [invocation setTarget:self];

            //设置select
            [invocation setSelector:getSel];

            //接收返回的值
            NSObject * __unsafe_unretained returnValue = nil;

            //调用
            [invocation invoke];

            //接收返回值
            [invocation getReturnValue:&returnValue];

            [resultString appendFormat:@"%@\n",returnValue];
        }
    }
    NSLog(@"%@",resultString);
}

简陋版的数据模型基类就已经完成了。注意,该模型中必须要属性名与key一致才能赋值成功。先看看运用模型基类的效果吧

创建实体模型类继承于模型基类,添加属性,属性名与测试用的字典的key一致。
@interface BeautifulBoyModel : BaseModel

@property (nonatomic, copy)NSString *boy0;
@property (nonatomic, copy)NSString *boy1;
@property (nonatomic, copy)NSString *boy2;
@property (nonatomic, copy)NSString *boy3;
@property (nonatomic, copy)NSString *boy4;
@property (nonatomic, copy)NSString *boy5;
@property (nonatomic, copy)NSString *boy6;
@property (nonatomic, copy)NSString *boy7;
@property (nonatomic, copy)NSString *boy8;
@property (nonatomic, copy)NSString *boy9;
@property (nonatomic, copy)NSString *boy10;
在main文件中,调用基类初始化方法,传入测试用的字典
BeautifulBoyModel *model = [BeautifulBoyModel modelWithDictionary:data];
        NSLog(@"%@",model.boy3);
        [model displayCurrentModelProperty];
输出结果

2016-06-14 14:36:16.426 Runtime[10815:924734] i am the 3 boy
2016-06-14 14:48:50.723 Runtime[10815:924734] i am the 0 boy
i am the 1 boy
i am the 2 boy
i am the 3 boy
i am the 4 boy
i am the 5 boy
i am the 6 boy
i am the 7 boy
i am the 8 boy
i am the 9 boy
i am the 10 boy

大功告成!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值