源码篇:Mantle

Mantle是一个用于简化Cocoa或Cocoa Touch程序中model层的第三方库。通常我们的应该中都会定义大量的model来表示各种数据结构,而这些model的初始化和编码解码都需要写大量的代码。而Mantle的优点在于能够大大地简化这些代码。

Mantle源码中最主要的内容包括:

  1. MTLModel类:通常是作为我们的Model的基类,该类提供了一些默认的行为来处理对象的初始化和归档操作,同时可以获取到对象所有属性的键值集合。
  2. MTLJSONAdapter类:用于在MTLModel对象和JSON字典之间进行相互转换,相当于是一个适配器。
  3. MTLJSONSerializing协议:需要与JSON字典进行相互转换的MTLModel的子类都需要实现该协议,以方便MTLJSONApadter对象进行转换。

在此就以这三者作为我们的分析点。

基类MTLModel

MTLModel是一个抽象类,它主要提供了一些默认的行为来处理对象的初始化和归档操作。

初始化

MTLModel默认的初始化方法-init并没有做什么事情,只是调用了下[super init]。而同时,它提供了一个另一个初始化方法:

- (instancetype)initWithDictionary:(NSDictionary *)dictionaryValue error:(NSError **)error;

其中参数dictionaryValue是一个字典,它包含了用于初始化对象的key-value对。我们来看下它的具体实现:

- (instancetype)initWithDictionary:(NSDictionary *)dictionary error:(NSError **)error {
    ...

    for (NSString *key in dictionary) {

        // 1. 将value标记为__autoreleasing,这是因为在MTLValidateAndSetValue函数中,
        //    可以会返回一个新的对象存在在该变量中
        __autoreleasing id value = [dictionary objectForKey:key];

        // 2. value如果为NSNull.null,会在使用前将其转换为nil
        if ([value isEqual:NSNull.null]) value = nil;

        // 3. MTLValidateAndSetValue函数利用KVC机制来验证value的值对于key是否有效,
        //    如果无效,则使用使用默认值来设置key的值。
        //    这里同样使用了对象的KVC特性来将value值赋值给model对应于key的属性。
        //    有关MTLValidateAndSetValue的实现可参考源码,在此不做详细说明。
        BOOL success = MTLValidateAndSetValue(self, key, value, YES, error);
        if (!success) return nil;
    }

    ...
}

子类可以重写该方法,以在设置完对象的属性后做进一步的处理或初始化工作,不过需要记住的是:应该通过super来调用父类的实现。

获取属性的键(key)、值(value)

MTLModel类提供了一个类方法+propertyKeys,该方法返回所有@property声明的属性所对应的名称字符串的一个集合,但不包括只读属性和MTLModel自身的属性。在这个类方法会去遍历model的所有属性,如果属性是非只读且其ivar值不为NULL,则获取到表示属性名的字符串,并将其放入到集合中,其实现如下:

+ (NSSet *)propertyKeys {
    // 1. 如果对象中已有缓存的属性名的集合,则直接返回缓存。该缓存是放在一个关联对象中。
    NSSet *cachedKeys = objc_getAssociatedObject(self, MTLModelCachedPropertyKeysKey);
    if (cachedKeys != nil) return cachedKeys;

    NSMutableSet *keys = [NSMutableSet set];

    // 2. 遍历对象所有的属性
    //    enumeratePropertiesUsingBlock方法会沿着superclass链一直向上遍历到MTLModel,
    //    查找当前model所对应类的继承体系中所有的属性(不包括MTLModel),并对该属性执行block中的操作。
    //    有关enumeratePropertiesUsingBlock的实现可参考源码,在此不做详细说明。
    [self enumeratePropertiesUsingBlock:^(objc_property_t property, BOOL *stop) {
        mtl_propertyAttributes *attributes = mtl_copyPropertyAttributes(property);
        @onExit {
            free(attributes);
        };

        // 3. 过滤只读属性和ivar为NULL的属性
        if (attributes->readonly && attributes->ivar == NULL) return;

        // 4. 获取属性名字符串,并存储到集合中
        NSString *key = @(property_getName(property));
        [keys addObject:key];
    }];

    // 5. 将集合缓存到关联对象中。
    objc_setAs
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值