美文网首页
OC Runtime-JSON转Model

OC Runtime-JSON转Model

作者: Shuo_H | 来源:发表于2017-03-17 10:57 被阅读0次

    最近在学习OC Runtime,学习嘛最重要的是实践,所以记录一下在实践过程中实现的一个简单的JSON转Model练习项目。这个项目主要是利用Runtime机制中,获取Class的属性列表和属性的相关信息的能力。
    一、相关方法
    <code>
    objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)
    </code>
    <code>
    const char *property_getName(objc_property_t property)
    </code>
    <code>
    const char *property_getAttributes(objc_property_t property)
    </code>

    class_copyPropertyList可以获取类的属性列表
    property_getName可以获取属性名称
    property_getAttributes可以获取属性的类型等信息

    例如在User类中定义了属性name和age

    @interface User : NSObject
    @property (strong, nonatomic) NSString *name;
    @property (assign, nonatomic) NSInteger age;
    @end
    

    通过下面的代码

    Class clazz = [User class];
        u_int count;
        objc_property_t *properties = class_copyPropertyList(clazz, &count);
        for (int i = 0; i < count; i++) {
            const char *propName = property_getName(properties[i]);
            const char *propAttr = property_getAttributes(properties[i]);
            
            NSLog(@"%s: %s", propName, propAttr);
        }
    

    可以得到如下打印信息:

    name: T@"NSString",&,N,V_name
    age: T^q,N,V_age
    

    看到这些打印信息,心中已有一些眉目了吧。

    二、JSON转Model

       转换的过程其实最本质的是获取类的属性列表,然后和传递进来的json字典进行key值对照一一赋值即可。
       所以首先我们需要先拿到属性列表信息。
    
    -(NSMutableDictionary *)keyMapper {
        
        Class clazz = object_getClass(self);//当前类
        u_int count;//属性数量
        objc_property_t *properties = class_copyPropertyList(clazz, &count);//属性列表
        
        NSMutableDictionary *result = [NSMutableDictionary dictionary];
        //解析获取到的属性列表
        for (int i = 0; i < count; i++) {
            // 属性名称
            const char *key = property_getName(properties[i]);
            NSString *propName  = [NSString stringWithCString:key encoding:NSUTF8StringEncoding];
            // 属性信息 类似:T@"NSString<Optional>",&,N,V_name
            const char *attr = property_getAttributes(properties[i]);
            //将字符串分解为基本单元
            NSArray *attrArray = [[NSString stringWithCString:attr encoding:NSUTF8StringEncoding] componentsSeparatedByString:@","];
        
            NSArray *firstItems = [[attrArray.firstObject stringByReplacingOccurrencesOfString:@"\"" withString:@""] componentsSeparatedByString:@"@"];
            Class type;
            if (firstItems.count == 2) {
                NSArray *info = [[firstItems.lastObject stringByReplacingOccurrencesOfString:@">" withString:@""] componentsSeparatedByString:@"<"];
                //拿到属性的数据类型
                if (info.count == 2) {
                    NSString *typeStr = [info firstObject];
                    type = NSClassFromString(typeStr);
                } else {
                    type = NSClassFromString(firstItems.lastObject);
                }
            }
            [result setObject: type forKey: propName];
        }
        return result;
    }
    
        当然,服务器和客户端可能约定某些字段为Optional,或者客户端会在本地加一些计算属性,可以也可以通过添加协议的方式实现,而在获取属性列表的时候一并解析出来,最后在赋值时加以简单的验证即可。
    
    NSDictionary *keyMapper = [self keyMapper];
            for (NSString *key in keyMapper.allKeys) {
                // 属性信息
                PropertyInfo *propInfo = [keyMapper objectForKey:key];
                // 值
                id value = [dict objectForKey:key];
                /** 验证当前属性是否为Optional  */
                if (!propInfo.isOptional && value == nil) {
                    NSString *errMsg = [key stringByAppendingString:@" is can not nil!"];
                    *error = [NSError errorWithDomain:@"Json Error"
                                               code:1 userInfo:@{@"errMsg": errMsg}];
                    return self;
                }
                // 验证数据类型是否正确
                if (![value isKindOfClass:propInfo.type]) {
                    NSString *errMsg = [key stringByAppendingString:@": type inconsistency!"];
                    *error = [NSError errorWithDomain:@"Json Error"
                                               code:1 userInfo:@{@"errMsg": errMsg}];
                    return self;
                }
                if (value) [self setValue:value forKey:key];
            }
    

    相关文章

      网友评论

          本文标题:OC Runtime-JSON转Model

          本文链接:https://www.haomeiwen.com/subject/ofljnttx.html