美文网首页
MJExtension源码解析

MJExtension源码解析

作者: MoneyRobber | 来源:发表于2019-06-10 10:43 被阅读0次

核心代码

/**
 核心代码:
 */
- (instancetype)setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context error:(NSError *__autoreleasing *)error
{
    // 获得JSON对象
    keyValues = [keyValues JSONObject];
    
    MJExtensionAssertError([keyValues isKindOfClass:[NSDictionary class]], self, error, @"keyValues参数不是一个字典");
    
    @try {
        Class aClass = [self class];
        NSArray *allowedPropertyNames = [aClass totalAllowedPropertyNames];
        NSArray *ignoredPropertyNames = [aClass totalIgnoredPropertyNames];
        
        //通过封装的方法回调一个通过运行时编写的,用于返回属性列表的方法。
        [aClass enumerateProperties:^(MJProperty *property, BOOL *stop) {
            // 0.检测是否被忽略
            if (allowedPropertyNames.count && ![allowedPropertyNames containsObject:property.name]) return;
            if ([ignoredPropertyNames containsObject:property.name]) return;
            
            // 1.取出属性值
            id value = keyValues ;
            NSArray *propertyKeys = [property propertyKeysFromClass:aClass];
            for (MJPropertyKey *propertyKey in propertyKeys) {
                value = [propertyKey valueInObject:value];
            }
            
            // 值的过滤
            id newValue = [aClass getNewValueFromObject:self oldValue:value property:property];
            if (newValue) value = newValue;
            
            // 如果没有值,就直接返回
            if (!value || value == [NSNull null]) return;
            
            // 2.如果是模型属性
            MJPropertyType *type = property.type;
            Class typeClass = type.typeClass;
            Class objectClass = [property objectClassInArrayFromClass:[self class]];
            if (!type.isFromFoundation && typeClass) {
                value = [typeClass objectWithKeyValues:value context:context error:error];
            } else if (objectClass) {
                // string array -> url array
                if (objectClass == [NSURL class] && [value isKindOfClass:[NSArray class]]) {
                    NSMutableArray *urlArray = [NSMutableArray array];
                    for (NSString *string in value) {
                        if (![string isKindOfClass:[NSString class]]) continue;
                        [urlArray addObject:string.url];
                    }
                    value = urlArray;
                } else {
                    // 3.字典数组-->模型数组
                    value = [objectClass objectArrayWithKeyValuesArray:value context:context error:error];
                }
            } else if (typeClass == [NSString class]) {
                if ([value isKindOfClass:[NSNumber class]]) {
                    // NSNumber -> NSString
                    value = [value description];
                } else if ([value isKindOfClass:[NSURL class]]) {
                    // NSURL -> NSString
                    value = [value absoluteString];
                }
            } else if ([value isKindOfClass:[NSString class]]) {
                if (typeClass == [NSURL class]) {
                    // NSString -> NSURL
                    // 字符串转码
                    value = [value url];
                } else if (type.isNumberType) {
                    NSString *oldValue = value;
                    
                    // NSString -> NSNumber
                    value = [_numberFormatter numberFromString:oldValue];
                    
                    // 如果是BOOL
                    if (type.isBoolType) {
                        // 字符串转BOOL(字符串没有charValue方法)
                        // 系统会调用字符串的charValue转为BOOL类型
                        NSString *lower = [oldValue lowercaseString];
                        if ([lower isEqualToString:@"yes"] || [lower isEqualToString:@"true"]) {
                            value = @YES;
                        } else if ([lower isEqualToString:@"no"] || [lower isEqualToString:@"false"]) {
                            value = @NO;
                        }
                    }
                }
            }
            
            // 4.赋值
            [property setValue:value forObject:self];
        }];
        
        // 转换完毕
        if ([self respondsToSelector:@selector(keyValuesDidFinishConvertingToObject)]) {
            [self keyValuesDidFinishConvertingToObject];
        }
    } @catch (NSException *exception) {
        MJExtensionBuildError(error, exception.reason);
        NSLog(@"%@", exception);
    }
    return self;
}

获取对象的每一个属性,包括父类的属性,不包括NSObject,代码如下

+ (void)enumerateProperties:(MJPropertiesEnumeration)enumeration
{
    // 获得成员变量
    NSArray *cachedProperties = [self properties];
    
    // 遍历成员变量
    BOOL stop = NO;
    for (MJProperty *property in cachedProperties) {
        enumeration(property, &stop);
        if (stop) break;
    }
}

取出属性值,代码如下

// 1.取出属性值
            id value = keyValues ;
            NSArray *propertyKeys = [property propertyKeysFromClass:aClass];
            for (MJPropertyKey *propertyKey in propertyKeys) {
                value = [propertyKey valueInObject:value];
            }

对象类型的值的处理,经过循环处理最终变成非对象,非数组的类型,代码如下

value = [typeClass objectWithKeyValues:value context:context error:error];

数组类型的值的处理,经过循环处理最终变成非对象,非数组的类型,代码如下

value = [objectClass objectArrayWithKeyValuesArray:value context:context error:error];

赋值,代码如下

[property setValue:value forObject:self];

MJExtension做了兼容处理,例如NSNumber,NSURL类型可以转换为NSString,代码如下

else if (typeClass == [NSString class]) {
                if ([value isKindOfClass:[NSNumber class]]) {
                    // NSNumber -> NSString
                    value = [value description];
                } else if ([value isKindOfClass:[NSURL class]]) {
                    // NSURL -> NSString
                    value = [value absoluteString];
                }
            }

相关文章

网友评论

      本文标题:MJExtension源码解析

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