JSONModel源码

news/2024/7/20 20:11:57 标签: ios, objective-c

参考博客:

JSONModel源码解析

JSONModel初始化方法

JSONModel对外给出了许多常见的初始化方法:

- (instancetype)initWithDictionary:(NSDictionary *)dict error:(NSError **)err;
- (instancetype)initWithData:(NSData *)data error:(NSError **)error;
// 创建一个新的模型实例,并使用来自文本参数的JSON初始化它。 
// 该方法假定输入文本为UTF8编码。
- (instancetype)initWithString:(NSString *)string error:(JSONModelError **)err;
// 创建一个新的模型实例,并使用使用给定编码的文本参数的JSON初始化它。
- (instancetype)initWithString:(NSString *)string usingEncoding:(NSStringEncoding)encoding error:(JSONModelError **)err;

让我们来看看其实现:

- (instancetype)initWithData:(NSData *)data error:(NSError *__autoreleasing *)err
{
    //check for nil input
    if (!data) {
        if (err) *err = [JSONModelError errorInputIsNil];
        return nil;
    }
    //read the json
    JSONModelError* initError = nil;
    id obj = [NSJSONSerialization JSONObjectWithData:data
                                             options:kNilOptions
                                               error:&initError];
    if (initError) {
        if (err) *err = [JSONModelError errorBadJSON];
        return nil;
    }
    //init with dictionary
    id objModel = [self initWithDictionary:obj error:&initError];
    if (initError && err) *err = initError;
    return objModel;
}

- (id)initWithString:(NSString*)string error:(JSONModelError**)err
{
    JSONModelError* initError = nil;
    id objModel = [self initWithString:string usingEncoding:NSUTF8StringEncoding error:&initError];
    if (initError && err) *err = initError;
    return objModel;
}

- (id)initWithString:(NSString *)string usingEncoding:(NSStringEncoding)encoding error:(JSONModelError**)err
{
    //check for nil input
    if (!string) {
        if (err) *err = [JSONModelError errorInputIsNil];
        return nil;
    }
    JSONModelError* initError = nil;
    id objModel = [self initWithData:[string dataUsingEncoding:encoding] error:&initError];
    if (initError && err) *err = initError;
    return objModel;
}

我们发现,这几个初始化方法最终实际上都还是调用了:

- (id)initWithDictionary:(NSDictionary*)dict error:(NSError**)err;

这个方法可以说是核心方法,让我们来看看他的实现如何。

-(id)initWithDictionary:(NSDictionary*)dict error:(NSError**)err
{
    //check for nil input
    //1.为空判断
    if (!dict) {
        if (err) *err = [JSONModelError errorInputIsNil];
        return nil;
    }

    //invalid input, just create empty instance
    //2.类型判断
    if (![dict isKindOfClass:[NSDictionary class]]) {
        if (err) *err = [JSONModelError errorInvalidDataWithMessage:@"Attempt to initialize JSONModel object using initWithDictionary:error: but the dictionary parameter was not an 'NSDictionary'."];
        return nil;
    }

    //create a class instance
    //3.核心,初始化映射property
    self = [self init];
    if (!self) {

        //super init didn't succeed
        if (err) *err = [JSONModelError errorModelIsInvalid];
        return nil;
    }

    //check incoming data structure
    //4.检查映射结构是否能够从dictionary中找到相应的数据
    if (![self __doesDictionary:dict matchModelWithKeyMapper:self.__keyMapper error:err]) {
        return nil;
    }

    //import the data from a dictionary
    //5.进行数据赋值
    if (![self __importDictionary:dict withKeyMapper:self.__keyMapper validation:YES error:err]) {
        return nil;
    }

    //run any custom model validation
    //6.本地数据检查
    if (![self validate:err]) {
        return nil;
    }

    //model is valid! yay!
    return self;
}

主要分为以下6块:

  • 1.空值判断
  • 2.输入类型dictionary判断
  • 3.初始化:解析model对象,并且映射property
  • 4.查值:检查model property名与数据来源json字典中数据名,判断是否所有property都有值
  • 5.赋值:进行赋值
  • 6.本地数据正确性检查

以下我将主要解析3,4,5这三部分的主代码。

初始化

  -(void)__setup__
{
    //if first instance of this model, generate the property list
    //使用AssociateObject进行映射property的缓存,判断是否映射过
    if (!objc_getAssociatedObject(self.class, &kClassPropertiesKey)) {
        [self __inspectProperties];
    }

    //if there's a custom key mapper, store it in the associated object
    //获取对象的keyMapper影射,同样使用AssociateObject进行映射property的缓存
    id mapper = [[self class] keyMapper];
    if ( mapper && !objc_getAssociatedObject(self.class, &kMapperObjectKey) ) {
        objc_setAssociatedObject(
                                 self.class,
                                 &kMapperObjectKey,
                                 mapper,
                                 OBJC_ASSOCIATION_RETAIN // This is atomic
                                 );
    }
}

-(id)init
{
    self = [super init];
    if (self) {
        //do initial class setup
        [self __setup__];
    }
    return self;
}

其中的kClassPropertiesKey和kMapperObjectKey都是JSONModel所持有的数据,如下:

关联对象kClassPropertiesKey:(用来保存所有属性信息的NSDictionary)
关联对象kClassRequiredPropertyNamesKey:(用来保存所有属性的名称NSSet)
关联对象kMapperObjectKey:(用来保存JSONKeyMapper):自定义的mapper,具体的使用方法在上面的例子中可以看到。
JSONModelClassProperty: 封装的jsonmodel的一个属性,它包含了对应属性的名字(name:sex),类型(type:NSString),是否是JSONModel支持的类型(isStandardJSONType:YES/NO),是否是可变对象(isMutable:YES/NO)等属性。

这段代码使用AssociateObject的缓存判断kClassPropertiesKey就知道该model对象是否有进行过解析property,没有的话进行解析,同时取出model的key mapper,也同样进行缓存。
key mapper主要是用来针对某些json字段名和model数据名不一致的情况。

上方代码中__setup__方法中调用了一个__inspectProperties:方法,这个方法是这个框架的核心方法之一:它的任务是保存了所有需要赋值的属性,用作将来与传进来的字典进行映射。具体代码实现如下:

//该__inspectProperties方法是该第三方框架的核心方法之一:它的任务是保存了所有需要赋值的属性。用作在将来与传进来的字典进行映射
//inspects the class, get's a list of the class properties
//检查类,获取类属性列表
-(void)__inspectProperties
{
    //JMLog(@"Inspect class: %@", [self class]);

    
    //    最终保存所有属性的字典,形式为(例子):
    //    {
    //        age = "@property primitive age (Setters = [])";
    //        friends = "@property NSArray* friends (Standard JSON type, Setters = [])";
    //        gender = "@property NSString* gender (Standard JSON type, Setters = [])";
    //        name = "@property NSString* name (Standard JSON type, Setters = [])";
    //    }
    NSMutableDictionary* propertyIndex = [NSMutableDictionary dictionary];

    //temp variables for the loops
    //循环的温度变量
    //获取当前的类名
    Class class = [self class];
    NSScanner* scanner = nil;
    NSString* propertyType = nil;

    // inspect inherited properties up to the JSONModel class
    //检查继承到JSONModel类的属性
    //循环条件:当class是JSONModel自己的时候不执行
    while (class != [JSONModel class]) {
        //JMLog(@"inspecting: %@", NSStringFromClass(class));
        
        //属性的个数
        unsigned int propertyCount;
        //获得属性列表(所有@property声明的属性)
        objc_property_t *properties = class_copyPropertyList(class, &propertyCount);

        //loop over the class properties
        //循环遍历所有的属性
        for (unsigned int i = 0; i < propertyCount; i++) {
            //JSONModel里的每一个属性,都被封装成一个JSONModelClassProperty对象
            JSONModelClassProperty* p = [[JSONModelClassProperty alloc] init];

            //get property name
            //获得属性名称
            objc_property_t property = properties[i];//获得当前属性
            const char *propertyName = property_getName(property);//name(C字符串)
            p.name = @(propertyName);//propertyNeme:属性名称,例如:name,age,gender

            //JMLog(@"property: %@", p.name);

            //get property attributes
            //获得属性类型
            const char *attrs = property_getAttributes(property);
            NSString* propertyAttributes = @(attrs);
            // T@\"NSString\",C,N,V_name
            // Tq,N,V_age
            // T@\"NSString\",C,N,V_gender
            // T@"NSArray",&,N,V_friends
            NSArray* attributeItems = [propertyAttributes componentsSeparatedByString:@","];

            //ignore read-only properties
            //说明是只读属性,不做任何操作
            if ([attributeItems containsObject:@"R"]) {
                continue; //to next property到下一个属性
            }
            
            //实例化一个scanner(扫描仪,用于查找相关字符串等功能)
            scanner = [NSScanner scannerWithString: propertyAttributes];

            //JMLog(@"attr: %@", [NSString stringWithCString:attrs encoding:NSUTF8StringEncoding]);
            [scanner scanUpToString:@"T" intoString: nil];
            [scanner scanString:@"T" intoString:nil];

            //check if the property is an instance of a class检查属性是否为类的实例
            if ([scanner scanString:@"@\"" intoString: &propertyType]) {
                //属性是一个对象
                [scanner scanUpToCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@"\"<"]
                                        intoString:&propertyType];//propertyType -> NSString

                //JMLog(@"type: %@", propertyClassName);
                p.type = NSClassFromString(propertyType);// p.type = @"NSString"
                p.isMutable = ([propertyType rangeOfString:@"Mutable"].location != NSNotFound);//判断是否是可变的对象
                p.isStandardJSONType = [allowedJSONTypes containsObject:p.type];//是否是该框架兼容的类型

                //read through the property protocols
                //通读属性协议
                //存在协议(数组,也就是嵌套模型)
                while ([scanner scanString:@"<" intoString:NULL]) {

                    NSString* protocolName = nil;

                    [scanner scanUpToString:@">" intoString: &protocolName];

                    if ([protocolName isEqualToString:@"Optional"]) {
                        p.isOptional = YES;
                    } else if([protocolName isEqualToString:@"Index"]) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
                        p.isIndex = YES;
#pragma GCC diagnostic pop

                        objc_setAssociatedObject(
                                                 self.class,
                                                 &kIndexPropertyNameKey,
                                                 p.name,
                                                 OBJC_ASSOCIATION_RETAIN // This is atomic这是原子的
                                                 );
                    } else if([protocolName isEqualToString:@"Ignore"]) {
                        p = nil;
                    } else {
                        p.protocol = protocolName;
                    }
                    //到最接近的>为止
                    [scanner scanString:@">" intoString:NULL];
                }

            }
            //check if the property is a structure检查属性是否为结构体
            else if ([scanner scanString:@"{" intoString: &propertyType]) {
                //属性是结构体
                [scanner scanCharactersFromSet:[NSCharacterSet alphanumericCharacterSet]
                                    intoString:&propertyType];

                p.isStandardJSONType = NO;
                p.structName = propertyType;

            }
            //the property must be a primitive
            //属性是基本类型
            else {
                //属性是基本类型:Tq、N、V_age
                //the property contains a primitive data type
                [scanner scanUpToCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@","]
                                        intoString:&propertyType];

                //get the full name of the primitive type
                //获取基元类型的全名
                //propertyType:q
                propertyType = valueTransformer.primitivesNames[propertyType];
                //propertyType:lone
                //基本类型数组
                if (![allowedPrimitiveTypes containsObject:propertyType]) {

                    //type not allowed - programmer mistaken -> exception
                    //类型不允许-程序员错误->异常
                    @throw [NSException exceptionWithName:@"JSONModelProperty type not allowed"
                                                   reason:[NSString stringWithFormat:@"Property type of %@.%@ is not supported by JSONModel.", self.class, p.name]
                                                 userInfo:nil];
                }

            }

            NSString *nsPropertyName = @(propertyName);
            //可选的
            if([[self class] propertyIsOptional:nsPropertyName]){
                p.isOptional = YES;
            }
            
            //可忽略的
            if([[self class] propertyIsIgnored:nsPropertyName]){
                p = nil;
            }
            
            //集合类
            Class customClass = [[self class] classForCollectionProperty:nsPropertyName];
            if (customClass) {
                p.protocol = NSStringFromClass(customClass);
            }

            //few cases where JSONModel will ignore properties automatically
            //很少有JSONModel会自动忽略属性的情况
            //忽略block
            if ([propertyType isEqualToString:@"Block"]) {
                p = nil;
            }

            //add the property object to the temp index
            //将属性对象添加到临时索引
            //如果字典里不存在,则添加到属性字典里(终于添加上去了。。。)
            if (p && ![propertyIndex objectForKey:p.name]) {
                [propertyIndex setValue:p forKey:p.name];
            }

            // generate custom setters and getter
            //生成自定义setter和getter
            if (p)
            {
                //name -> Name(大写p的名字属性的前两个字母)
                NSString *name = [p.name stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:[p.name substringToIndex:1].uppercaseString];

                // getter
                SEL getter = NSSelectorFromString([NSString stringWithFormat:@"JSONObjectFor%@", name]);

                if ([self respondsToSelector:getter])
                    p.customGetter = getter;

                // setters
                p.customSetters = [NSMutableDictionary new];

                SEL genericSetter = NSSelectorFromString([NSString stringWithFormat:@"set%@WithJSONObject:", name]);

                if ([self respondsToSelector:genericSetter])
                    p.customSetters[@"generic"] = [NSValue valueWithBytes:&genericSetter objCType:@encode(SEL)];

                for (Class type in allowedJSONTypes)
                {
                    NSString *class = NSStringFromClass([JSONValueTransformer classByResolvingClusterClasses:type]);

                    if (p.customSetters[class])
                        continue;

                    SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set%@With%@:", name, class]);

                    if ([self respondsToSelector:setter])
                        p.customSetters[class] = [NSValue valueWithBytes:&setter objCType:@encode(SEL)];
                }
            }
        }
        //释放属性列表
        free(properties);

        //ascend to the super of the class
        //(will do that until it reaches the root class - JSONModel)
        //升到class上的最高级
        //(将这样做,直到它到达根类-JSONModel)再指向自己的父类,直到等于JSONModel才停止
        class = [class superclass];
    }

    //finally store the property index in the static property index
    //最后将属性索引(属性列表)存储在静态属性索引中
    //(最后保存所有当前类,JSONModel的所有的父类的属性)
    objc_setAssociatedObject(
                             self.class,
                             &kClassPropertiesKey,
                             [propertyIndex copy],
                             OBJC_ASSOCIATION_RETAIN // This is atomic这是原子的
                             );
}

简单来说就是:
使用runtime的class_copyPropertyList方法去获得所有model对象的property列表,再使用
property_getAttributes获得property的encode string,通过解析encode string去获得property对象的正确含义。
在解析的过程中,使用NSScanner去扫描encode string,并使用JSONModelClassProperty的结构体去保存相关信息。
其中对于protocol的使用较为特殊,在这里的protocol并非我们平常当作接口抽象的作用,而是单纯的为了让encode string中增加相应的字段,可以在解析与赋值的时候给予特定的含义。

__doesDictionary方法:

//model类里面定义的属性集合是不能大于传入的字典里的key集合的。
//如果存在了用户自定义的mapper,则需要按照用户的定义来进行转换。
//(例如将gender转换为了sex)。
-(BOOL)__doesDictionary:(NSDictionary*)dict matchModelWithKeyMapper:(JSONKeyMapper*)keyMapper error:(NSError**)err
{
    //check if all required properties are present
    //拿到字典里所有的key
    NSArray* incomingKeysArray = [dict allKeys];
    NSMutableSet* requiredProperties = [self __requiredPropertyNames].mutableCopy;
    //从array拿到set
    NSSet* incomingKeys = [NSSet setWithArray: incomingKeysArray];

    //transform the key names, if necessary
    //如有必要,变换键名称
    //如果用户自定义了mapper,则进行转换
    if (keyMapper || globalKeyMapper) {

        NSMutableSet* transformedIncomingKeys = [NSMutableSet setWithCapacity: requiredProperties.count];
        NSString* transformedName = nil;

        //loop over the required properties list
        //在所需属性列表上循环
        //遍历需要转换的属性列表
        for (JSONModelClassProperty* property in [self __properties__]) {
            //被转换成的属性名称(例如)gender(模型内) -> sex(字典内)
            transformedName = (keyMapper||globalKeyMapper) ? [self __mapString:property.name withKeyMapper:keyMapper] : property.name;

            //check if exists and if so, add to incoming keys
            //检查是否存在,如果存在,则添加到传入密钥
            //(例如)拿到sex以后,查看传入的字典里是否有sex对应的值
            id value;
            @try {
                value = [dict valueForKeyPath:transformedName];
            }
            @catch (NSException *exception) {
                value = dict[transformedName];
            }

            if (value) {
                [transformedIncomingKeys addObject: property.name];
            }
        }

        //overwrite the raw incoming list with the mapped key names
        //用映射的键名称覆盖原始传入列表
        incomingKeys = transformedIncomingKeys;
    }

    //check for missing input keys
    //检查是否缺少输入键
    //查看当前的model的属性的集合是否大于传入的属性集合,如果是,则返回错误
    //也就是说模型类里的属性是不能多于传入字典里的key的,例如:
    if (![requiredProperties isSubsetOfSet:incomingKeys]) {

        //get a list of the missing properties
        //获取缺失属性的列表(获取多出来的属性)
        [requiredProperties minusSet:incomingKeys];

        //not all required properties are in - invalid input
        //并非所有必需的属性都在 in - 输入无效
        JMLog(@"Incoming data was invalid [%@ initWithDictionary:]. Keys missing: %@", self.class, requiredProperties);

        if (err) *err = [JSONModelError errorInvalidDataWithMissingKeys:requiredProperties];
        return NO;
    }

    //not needed anymore
    //不再需要了,释放掉
    incomingKeys= nil;
    requiredProperties= nil;

    return YES;
}

检查一下所有的必要属性都存在,并且把他们都放入set中 。如果缺少值则抛出错误。

__importDictionary:方法:

-(BOOL)__importDictionary:(NSDictionary*)dict withKeyMapper:(JSONKeyMapper*)keyMapper validation:(BOOL)validation error:(NSError**)err
{
    //loop over the incoming keys and set self's properties
    //循环遍历映射出来的JSONModelClassProperty结构体
    for (JSONModelClassProperty* property in [self __properties__]) {

        //convert key name ot model keys, if a mapper is provided
        //keyMapper映射,获取镇真正的值
        NSString* jsonKeyPath = (keyMapper||globalKeyMapper) ? [self __mapString:property.name withKeyMapper:keyMapper importing:YES] : property.name;
        //JMLog(@"keyPath: %@", jsonKeyPath);

        //general check for data type compliance
        id jsonValue;
        @try {
            jsonValue = [dict valueForKeyPath: jsonKeyPath];
        }
        @catch (NSException *exception) {
            jsonValue = dict[jsonKeyPath];
        }

        //check for Optional properties
        if (isNull(jsonValue)) {
            //skip this property, continue with next property
            if (property.isOptional || !validation) continue;

            if (err) {
                //null value for required property
                NSString* msg = [NSString stringWithFormat:@"Value of required model key %@ is null", property.name];
                JSONModelError* dataErr = [JSONModelError errorInvalidDataWithMessage:msg];
                *err = [dataErr errorByPrependingKeyPathComponent:property.name];
            }
            return NO;
        }

        Class jsonValueClass = [jsonValue class];
        BOOL isValueOfAllowedType = NO;

        //判断数据输入类型是不是允许的json类型
        for (Class allowedType in allowedJSONTypes) {
            if ( [jsonValueClass isSubclassOfClass: allowedType] ) {
                isValueOfAllowedType = YES;
                break;
            }
        }

        if (isValueOfAllowedType==NO) {
            //type not allowed
            JMLog(@"Type %@ is not allowed in JSON.", NSStringFromClass(jsonValueClass));

            if (err) {
                NSString* msg = [NSString stringWithFormat:@"Type %@ is not allowed in JSON.", NSStringFromClass(jsonValueClass)];
                JSONModelError* dataErr = [JSONModelError errorInvalidDataWithMessage:msg];
                *err = [dataErr errorByPrependingKeyPathComponent:property.name];
            }
            return NO;
        }

        //check if there's matching property in the model
        if (property) {

            // check for custom setter, than the model doesn't need to do any guessing
            // how to read the property's value from JSON
            // 使用对象相应的setter方法进行set
            if ([self __customSetValue:jsonValue forProperty:property]) {
                //skip to next JSON key
                continue;
            };

            // 0) handle primitives
            // 代表基础类型,比如int float等,直接使用kvc赋值
            if (property.type == nil && property.structName==nil) {

                //generic setter
                if (jsonValue != [self valueForKey:property.name]) {
                    [self setValue:jsonValue forKey: property.name];
                }

                //skip directly to the next key
                continue;
            }

            // 0.5) handle nils
            if (isNull(jsonValue)) {
                if ([self valueForKey:property.name] != nil) {
                    [self setValue:nil forKey: property.name];
                }
                continue;
            }


            // 1) check if property is itself a JSONModel
            // 判断子结构是否是一个JSONModel结构,进行递归遍历,先将子结构遍历完并赋值完成
            if ([self __isJSONModelSubClass:property.type]) {

                //initialize the property's model, store it
                JSONModelError* initErr = nil;
                id value = [[property.type alloc] initWithDictionary: jsonValue error:&initErr];

                if (!value) {
                    //skip this property, continue with next property
                    if (property.isOptional || !validation) continue;

                    // Propagate the error, including the property name as the key-path component
                    if((err != nil) && (initErr != nil))
                    {
                        *err = [initErr errorByPrependingKeyPathComponent:property.name];
                    }
                    return NO;
                }
                if (![value isEqual:[self valueForKey:property.name]]) {
                    [self setValue:value forKey: property.name];
                }

                //for clarity, does the same without continue
                continue;

            } else {

                // 2) check if there's a protocol to the property
                //  ) might or not be the case there's a built in transform for it
                // 是否包含protocol的字段,该字段主要用来表明array或者dictionary中的对象类型
                if (property.protocol) {

                    //JMLog(@"proto: %@", p.protocol);
                    //循环遍历子内容,将对应的类型赋给相应的array或者dictionary
                    jsonValue = [self __transform:jsonValue forProperty:property error:err];
                    if (!jsonValue) {
                        if ((err != nil) && (*err == nil)) {
                            NSString* msg = [NSString stringWithFormat:@"Failed to transform value, but no error was set during transformation. (%@)", property];
                            JSONModelError* dataErr = [JSONModelError errorInvalidDataWithMessage:msg];
                            *err = [dataErr errorByPrependingKeyPathComponent:property.name];
                        }
                        return NO;
                    }
                }

                // 3.1) handle matching standard JSON types
                // 判断标准的json类型,比如nsstring等
                if (property.isStandardJSONType && [jsonValue isKindOfClass: property.type]) {

                    //mutable properties
                    if (property.isMutable) {
                        jsonValue = [jsonValue mutableCopy];
                    }

                    //set the property value
                    if (![jsonValue isEqual:[self valueForKey:property.name]]) {
                        [self setValue:jsonValue forKey: property.name];
                    }
                    continue;
                }

                // 3.3) handle values to transform
                // 其他处理情况,主要是一些类型转换的情况,比如nsstring转换为nsurl等
                if (
                    (![jsonValue isKindOfClass:property.type] && !isNull(jsonValue))
                    ||
                    //the property is mutable
                    property.isMutable
                    ||
                    //custom struct property
                    property.structName
                    ) {

                    // searched around the web how to do this better
                    // but did not find any solution, maybe that's the best idea? (hardly)
                    // 获取真实的json数据类型
                    Class sourceClass = [JSONValueTransformer classByResolvingClusterClasses:[jsonValue class]];

                    //JMLog(@"to type: [%@] from type: [%@] transformer: [%@]", p.type, sourceClass, selectorName);

                    //build a method selector for the property and json object classes
                    // 通过property类型和json数据类型进行转换的判断
                    NSString* selectorName = [NSString stringWithFormat:@"%@From%@:",
                                              (property.structName? property.structName : property.type), //target name
                                              sourceClass]; //source name
                    SEL selector = NSSelectorFromString(selectorName);

                    //check for custom transformer
                    //是否有本地转换的方法
                    BOOL foundCustomTransformer = NO;
                    if ([valueTransformer respondsToSelector:selector]) {
                        foundCustomTransformer = YES;
                    } else {
                        //try for hidden custom transformer
                        selectorName = [NSString stringWithFormat:@"__%@",selectorName];
                        selector = NSSelectorFromString(selectorName);
                        if ([valueTransformer respondsToSelector:selector]) {
                            foundCustomTransformer = YES;
                        }
                    }

                    //check if there's a transformer with that name
                    if (foundCustomTransformer) {

                        //it's OK, believe me...
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
                        //transform the value
                        // 通过 JSONValueTransformer 进行类型转换
                        jsonValue = [valueTransformer performSelector:selector withObject:jsonValue];
#pragma clang diagnostic pop

                        if (![jsonValue isEqual:[self valueForKey:property.name]]) {
                            [self setValue:jsonValue forKey: property.name];
                        }

                    } else {

                        // it's not a JSON data type, and there's no transformer for it
                        // if property type is not supported - that's a programmer mistake -> exception
                        @throw [NSException exceptionWithName:@"Type not allowed"
                                                       reason:[NSString stringWithFormat:@"%@ type not supported for %@.%@", property.type, [self class], property.name]
                                                     userInfo:nil];
                        return NO;
                    }

                } else {
                    // 3.4) handle "all other" cases (if any)
                    if (![jsonValue isEqual:[self valueForKey:property.name]]) {
                        [self setValue:jsonValue forKey: property.name];
                    }
                }
            }
        }
    }

    return YES;
}

这是从字典里获取值并赋值给当前模型对象的实现。
操作如下:

循环遍历映射出来的JSONModelClassProperty
2、获取keyMapper的映射,获取真正的值
3、判断数据输入的类型是不是我们允许的json类型
4、检查model中是否有匹配的属性
5、检查自定义的setter,使用对应的set进行赋值—-(这个具体看代码里面的判断,我就不列举出来了)
6、处理一些转化类型,比如string <-> number、string <-> url


http://www.niftyadmin.cn/n/229950.html

相关文章

「C/C++」编写程序代码命名规范

目录说明文件命名规则函数命名规则类型命名规则常量与宏命名变量命名规则说明 代码命名必须易于阅读和维护&#xff0c;在表达出意思的基础上命名越简洁越好&#xff0c;那么形成规范就尤为重要&#xff0c;以下为一些常用命名法&#xff1a; 驼峰命名法&#xff08;CamelCase&…

利用全连接神经网络对车辆进行识别

import os import zipfile import random import paddle import numpy as np import matplotlib.pyplot as plt import PIL.Image as Image from paddle.io import Dataset(1)import os&#xff1a;导入操作系统&#xff08;OS&#xff09;模块&#xff0c;该模块提供了一种与文…

【大数据专栏】字段归零的问题

在库&#xff08;mysql版本号&#xff1a;8.0.29&#xff09;表结构做比对的时候&#xff0c;发现很多字段保存后归零。 原因分析&#xff1a;根据告警的提示信息指出&#xff1a;integer的宽度显示将在未来版本被移除。根据数据库管理工具的使用&#xff0c;mysqlint数据类型不…

数据仓库的概念及与数据库等对比

1、什么是数据仓库&#xff1f; 数据仓库是信息&#xff08;对其进行分析可做出更明智的决策&#xff09;的中央存储库。通常&#xff0c;数据定期从事务系统、关系数据库和其他来源流入数据仓库。业务分析师、数据工程师、数据科学家和决策者通过商业智能 (BI) 工具、SQL 客户…

linux-创建子进程的过程与原理(fork讲解)

我们知道&#xff0c;子进程可以被命令行创建&#xff0c;被fork函数创建&#xff0c;但是子进程创建了什么呢&#xff0c;是完全拷贝父进程函数&#xff1f;还是继承父进程数据呢&#xff1f; 首先我们要知道&#xff0c;进程的构成&#xff1a;进程内核数据结构可运行程序载…

什么是数字人?数字人可以应用在哪些行业?

数字人指的是由计算机技术、人工智能技术和大数据技术等多种技术手段构建的一种虚拟的人类形态。数字人通常具备丰富的信息处理能力、模拟能力和学习能力&#xff0c;可以根据人们的需求进行智能化定制服务。 数字人 在很多行业领域&#xff0c;数字人都被广泛应用&#xff0…

C++初阶 -1- C++入门

文章目录0.什么是C1.C关键字2.命名空间导入什么是命名空间命名空间的使用3.C 输入&输出4.缺省参数什么是缺省参数缺省参数的应用场景5.函数重载0.什么是C C是基于C语言而产生的&#xff0c;它既可以进行C语言的过程化程序设计&#xff0c;又可以进行以抽象数据类型为特点的…

Linux | 计算机网络

网络 端口号 www的端口&#xff1a;80 ftp的端口&#xff1a;20和21 netstat、路由 netstat&#xff1a;显示 网络 状态&#xff0c;linux下可以得知整个 Linux 系统、本机各端口的网络情况&#xff0c;查看当前网络连接、查看主机的连接状态&#xff0c;一般用于检验本机各…