美文网首页技术分享
YYModel源码分析(三)

YYModel源码分析(三)

作者: fire_fire | 来源:发表于2016-06-27 14:51 被阅读247次

话不多说,下面直接开始分析设置值的核心方法,代码如下:

- (BOOL)modelSetWithDictionary:(NSDictionary *)dic {
    if (!dic || dic == (id)kCFNull) return NO;
    if (![dic isKindOfClass:[NSDictionary class]]) return NO;
    // 模型元数据
    _YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:object_getClass(self)];
    // 没有key->property直接返回
    if (modelMeta->_keyMappedCount == 0) return NO;
    
    // 在这里能修改数据源字典
    if (modelMeta->_hasCustomWillTransformFromDictionary) {
        dic = [((id<YYModel>)self) modelCustomWillTransformFromDictionary:dic];
        if (![dic isKindOfClass:[NSDictionary class]]) return NO;
    }
    
    // 结构体
    ModelSetContext context = {0};
    context.modelMeta = (__bridge void *)(modelMeta);
    context.model = (__bridge void *)(self);
    context.dictionary = (__bridge void *)(dic);
    
    // 为属性设值
    if (modelMeta->_keyMappedCount >= CFDictionaryGetCount((CFDictionaryRef)dic)) {
        CFDictionaryApplyFunction((CFDictionaryRef)dic, ModelSetWithDictionaryFunction, &context);
        if (modelMeta->_keyPathPropertyMetas) {
            CFArrayApplyFunction((CFArrayRef)modelMeta->_keyPathPropertyMetas,
                                 CFRangeMake(0, CFArrayGetCount((CFArrayRef)modelMeta->_keyPathPropertyMetas)),
                                 ModelSetWithPropertyMetaArrayFunction,
                                 &context);
        }
        if (modelMeta->_multiKeysPropertyMetas) {
            CFArrayApplyFunction((CFArrayRef)modelMeta->_multiKeysPropertyMetas,
                                 CFRangeMake(0, CFArrayGetCount((CFArrayRef)modelMeta->_multiKeysPropertyMetas)),
                                 ModelSetWithPropertyMetaArrayFunction,
                                 &context);
        }
    } else {
        CFArrayApplyFunction((CFArrayRef)modelMeta->_allPropertyMetas,
                             CFRangeMake(0, modelMeta->_keyMappedCount),
                             ModelSetWithPropertyMetaArrayFunction,
                             &context);
    }
    
    // 返回YES表明该模型可用,返回NO忽略该模型
    if (modelMeta->_hasCustomTransformFromDictionary) {
        return [((id<YYModel>)self) modelCustomTransformFromDictionary:dic];
    }
    return YES;
}

其中ModelSetContext为作者定义的结构体,如下:

typedef struct {
    void *modelMeta;  ///< _YYModelMeta
    void *model;      ///< id (self)
    void *dictionary; ///< NSDictionary (json)
} ModelSetContext;
  • modelMeta 表示模型元数据
  • model 表示模型本身
  • dictionary 表示数据源字典
    此处有两个分支,当model的key->property大于等于数据源字典的key、value数量时,分别设置keyPath、多个key对应同一属性的值;另外一种情况直接设置所有的属性元数据的值。
    CFDictionaryApplyFunction为Core Foundation API,会为每个key/value对调用一次指定的方法。
    CFArrayApplyFunction会为数组内指定范围的每个元素调用一次指定的方法。
static void ModelSetWithDictionaryFunction(const void *_key, const void *_value, void *_context) {
    ModelSetContext *context = _context;
    __unsafe_unretained _YYModelMeta *meta = (__bridge _YYModelMeta *)(context->modelMeta);
    __unsafe_unretained _YYModelPropertyMeta *propertyMeta = [meta->_mapper objectForKey:(__bridge id)(_key)];
    __unsafe_unretained id model = (__bridge id)(context->model);
    // 多个property对应一个key,循环赋值
    while (propertyMeta) {
        if (propertyMeta->_setter) {
            // 赋值方法
            ModelSetValueForProperty(model, (__bridge __unsafe_unretained id)_value, propertyMeta);
        }
        propertyMeta = propertyMeta->_next;
    };
}

关于赋值方法ModelSetValueForProperty没有什么好讲的,就是根据model属性的类型来相应的赋值,其中会有一些字符串转换日期,字符串转换NSNumber等的方法调用。

static void ModelSetWithPropertyMetaArrayFunction(const void *_propertyMeta, void *_context) {
    ModelSetContext *context = _context;
    __unsafe_unretained NSDictionary *dictionary = (__bridge NSDictionary *)(context->dictionary);
    __unsafe_unretained _YYModelPropertyMeta *propertyMeta = (__bridge _YYModelPropertyMeta *)(_propertyMeta);
    if (!propertyMeta->_setter) return;
    id value = nil;
    
    if (propertyMeta->_mappedToKeyArray) {
        // 多个key对应同一属性赋值
        value = YYValueForMultiKeys(dictionary, propertyMeta->_mappedToKeyArray);
    } else if (propertyMeta->_mappedToKeyPath) {
        // keyPath赋值
        value = YYValueForKeyPath(dictionary, propertyMeta->_mappedToKeyPath);
    } else {
        value = [dictionary objectForKey:propertyMeta->_mappedToKey];
    }
    
    if (value) {
        __unsafe_unretained id model = (__bridge id)(context->model);
        ModelSetValueForProperty(model, value, propertyMeta);
    }
}

可以看到,多个key对应同一属性的优先级最高,keyPath其次,这样在返回自定义key->property对于同一属性多次设置时会忽略优先级低的赋值。

相关文章

  • YYImage/YYModel/YYCache

    1.YYImage源码分析2.YYModel源码分析3.郑钦洪_:YYModel 源码历险记model属性赋值过程...

  • YYModel源码分析(三)

    话不多说,下面直接开始分析设置值的核心方法,代码如下: 其中ModelSetContext为作者定义的结构体,如下...

  • YYModel源码分析

    前言 YYModel 是一个iOS JSON模型转化库,和其他一些同类型库相比,具有比较好的性能优势。本文会对YY...

  • iOS源码解析—YYModel(NSObject+YYModel

    概述 ​ iOS源码解析—YYModel(YYClassInfo)分析了如何根据OC的Class对象构建...

  • YYModel源码分析(一)

    本文章所使用的YYModel源码基于0.9.8版本。从截图来看,YYModel是由两个类构成,本章先着手分析YYC...

  • YYKit__YYImage_源码分析

    YYKit__YYModel_源码分析:http://www.jianshu.com/p/e1f477dddb47...

  • YYModel源码分析(一)

    基础知识记录 oc运行时定义的几种类型介绍:Class:objective-c中类的定义Ivar:对象的实例变量,...

  • YYModel源码分析(二)

    下面分析NSObject+YYModel的实现,从头文件可以看该类由三个Category和一个Protocol所组...

  • YYModel源码分析(二)

    前言 YYClassInfo该文件中定义了四个类,要了解这四个类我们需要了解一些runtime的知识。 YYCLa...

  • [iOS] YYmodel源码分析

    无聊小姐姐今天准备看下YYmodel啦~ https://github.com/ibireme/YYModel Y...

网友评论

    本文标题:YYModel源码分析(三)

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