chenzhao

  • java
  • iOS
  • IT
知识积累
不积跬步无以至千里
  1. 首页
  2. iOS
  3. 正文

OC Runtime 修改YYModel nil变空字符处理

2018年 8月 14日 76点热度 0人点赞 0条评论

YYModel 没有好的 如果变量为nil 替换一个默认变量,OC 中 NSString 经常容易nil 崩溃, 所以有了此次需求,
注: 有一定的性能损失, 但是无需求的话不实现替换方法,性能损失应该很小, 有需求,用性能换稳定应该也划算

NSObject+YYMolde.h 新增

/**
 转换完成后执行, 老变量新变量的替换
 (只遍历当前类, 忽略父类)
 @return <#return value description#>
 */
- (id)oldValueToNewValue:(id)value classTypeName:(const char *)classTypeName;

.m 新增

/**
 * 解析Property的Attributed字符串,参考Stackoverflow
 */
static const char *getPropertyType(objc_property_t property) {
    const char *attributes = property_getAttributes(property);
    
    //    NSLog(@"%s", attributes);
    
    char buffer[1 + strlen(attributes)];
    strcpy(buffer, attributes);
    char *state = buffer, *attribute;
    while ((attribute = strsep(&state, ",")) != NULL) {
        // 非对象类型
        if (attribute[0] == 'T' && attribute[1] != '@') {
            // 利用NSData复制一份字符串
            return (const char *) [[NSData dataWithBytes:(attribute + 1) length:strlen(attribute) - 1] bytes];
            // 纯id类型
        } else if (attribute[0] == 'T' && attribute[1] == '@' && strlen(attribute) == 2) {
            return "id";
            // 对象类型
        } else if (attribute[0] == 'T' && attribute[1] == '@') {
            return (const char *) [[NSData dataWithBytes:(attribute + 3) length:strlen(attribute) - 4] bytes];
        }
    }
    return "";
}


检查函数, 在合适的位置调用(model 转换完成后调用)

- (void)checkObj:(NSObject *)obj{
    if ([obj respondsToSelector:@selector(oldValueToNewValue:classTypeName:)]){
        @try{
            unsigned int outCount, i;
            //objc_property_t 数组获取
            objc_property_t *properties = class_copyPropertyList([obj class], &outCount);
            for (i = 0;i<outCount; i++){
                // 单一的 objc_property_t
                objc_property_t property = properties[i];
                // 变量名获取
                NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];
                // 获取类型名称
                const char * propertyTypeName = getPropertyType(property);
                // 获取 property 值
                id propertyValue = [obj valueForKey:propertyName];
                id newValue = [(id<YYModel>)obj oldValueToNewValue:propertyValue classTypeName:propertyTypeName];
                if (newValue != propertyValue){
                    [obj setValue:newValue forKey:propertyName];
                }
                
            }
            
            free(properties);
            // 如需遍历父类, 但是不需要的
            //            NSObject * subObj = obj.superclass;
            //            if (subObj){
            ////                NSLog(@"currentObj %@, subObjClassName---%@",[obj classForCoder],[subObj classForCoder]);
            //                [self checkObj:subObj];
            //            }
            
            
            
        }@catch(NSException *exp){
            
        }
    }
}

然后自己的实现model 中 实现, 其他类型判断都可行

- (id)oldValueToNewValue:(id)value classTypeName:(const char *)classTypeName{
    const char * className = NSStringFromClass([NSString class]).UTF8String;
    if (strncmp(className, classTypeName, strlen(className)) == 0){
        if(value == nil || value == NULL){
            return @"";
        }
    }
    return value;
}

重点 - 解析property_getAttributes函数的结果
在整个处理过程中,property_getAttributes函数是关键,因为我们要首先确定Property的类型,才能根据类型赋初值,但是property_getAttributes函数返回的字符串比较“晦涩难懂”:

如下定义的Property:

@property (copy, nonatomic) NSString *name;
@property (strong, nonatomic) NSNumber *number;
@property (strong, nonatomic) NSArray *array;
@property (assign, nonatomic) NSInteger i;
@property (assign, nonatomic) CGFloat f;
@property (assign, nonatomic) char *cStr;

依次通过property_getAttributes获取的结果是:

T@"NSString",C,N,V_name
T@"NSNumber",&,N,V_number
T@"NSArray",&,N,V_array
Tq,N,V_i
Td,N,V_f
T*,N,V_cStr

参考 Declared Properties of Objective-C Runtime Programming Guide
我们大概可以知道,T表示Type,后面跟着@表示Cocoa对象类型,后面的表示Property的属性,如Copy、strong等,然后就是变量名。
所以getPropertyType函数的工作就是纯粹的解析字符串,获取T@后面的类型名。

参考

git 地址

标签: 暂无
最后更新:2022年 11月 11日

陈昭

IT 程序员

打赏 点赞
< 上一篇
下一篇 >

文章评论

取消回复

COPYRIGHT © 2022 chenzhao. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang