六、Runtime 实践部分 之 YYModel 源码跟读

2017-05-03  本文已影响37人  upcode

本文github地址 https://github.com/ICZhuang/Runtime 朋友们如果喜欢收藏即可,不建议转载,笔者会不定期update文章,github 也会同步更新,喜欢就star一下吧。

想着继续介绍Runtime 的概念部分 关于Protocol,Category,还有objc_xxx API,但又想到这跟之前介绍的都有相通的地方,所以就不再拉长篇幅了。其中就“关联对象”还需要提一下,然而网络博客已经一大堆了,有些东西,毕竟没有去实际应用过,不好做总结,就在真正用到Runtime再详细的补上吧。

MJExtension 和 YYKit中的模型对象互转,是Runtime体现出目前最为广泛使用的方式之一。至于这里选择读YYKit没什么特殊原因,就是因为项目中使用的是YYKit,我想,看懂一个,在去看懂另外一个不是难事儿。。

YYClassInfo

看头文件,就知道,这个就是在获取一个类中的各部分的信息。该头文件声明了四个类YYClassInfo、YYClassPropertyInfo、 YYClassIvarInfo、YYClassMethodInfo,它们就是对应着将objc_class、objc_property、objc_ivar、objc_method封装成OC对象。

YYClassInfo的核心方法就是_update方法,在这个方法里,遍历class对象的各个部分,将它们封装成了对象放进属性中。

笔者认为,在有了前面的基础,看懂这个方法在做什么绝不是难事,这里笔者只提一下本人认为的比较巧妙的方法。就是对类型编码的处理方法。

YYEncodingType YYEncodingGetType(const char *typeEncoding);

关于类型编码,可参考官方文档

‘Objective-C Runtime Programming Guide > Type Encodings’

‘Objective-C Runtime Programming Guide > Declared Properties’

笔者译文 Type Encoding & Declared Propery

对编码的处理,YY大神将其字符串表示的编码转成用枚举标识,而理解的关键点也就在于枚举的运算,就是枚举的 &、| 操作。另外有一点需要知晓的是使用过的Class info会被缓存的。

在 Type Encodings 文档中谈及的有 类型编码和类型描述符编码,而在 Declared Properties 文档中谈及的则有访问属性的attribute的编码。关于这三类编码都在头文件中 YYEncodingType 的枚举中对应找到,YYKit就是将 C 字符串的形式转成用枚举来表示类型编码。

/**
 Type encoding's type.
 */
typedef NS_OPTIONS(NSUInteger, YYEncodingType) {
    YYEncodingTypeMask       = 0xFF, ///< mask of type value
    YYEncodingTypeUnknown    = 0, ///< unknown
    YYEncodingTypeVoid       = 1, ///< void
    YYEncodingTypeBool       = 2, ///< bool
    YYEncodingTypeInt8       = 3, ///< char / BOOL
    YYEncodingTypeUInt8      = 4, ///< unsigned char
    YYEncodingTypeInt16      = 5, ///< short
    YYEncodingTypeUInt16     = 6, ///< unsigned short
    YYEncodingTypeInt32      = 7, ///< int
    YYEncodingTypeUInt32     = 8, ///< unsigned int
    YYEncodingTypeInt64      = 9, ///< long long
    YYEncodingTypeUInt64     = 10, ///< unsigned long long
    YYEncodingTypeFloat      = 11, ///< float
    YYEncodingTypeDouble     = 12, ///< double
    YYEncodingTypeLongDouble = 13, ///< long double
    YYEncodingTypeObject     = 14, ///< id
    YYEncodingTypeClass      = 15, ///< Class
    YYEncodingTypeSEL        = 16, ///< SEL
    YYEncodingTypeBlock      = 17, ///< block
    YYEncodingTypePointer    = 18, ///< void*
    YYEncodingTypeStruct     = 19, ///< struct
    YYEncodingTypeUnion      = 20, ///< union
    YYEncodingTypeCString    = 21, ///< char*
    YYEncodingTypeCArray     = 22, ///< char[10] (for example)
    
    YYEncodingTypeQualifierMask   = 0xFF00,   ///< mask of qualifier
    YYEncodingTypeQualifierConst  = 1 << 8,  ///< const
    YYEncodingTypeQualifierIn     = 1 << 9,  ///< in
    YYEncodingTypeQualifierInout  = 1 << 10, ///< inout
    YYEncodingTypeQualifierOut    = 1 << 11, ///< out
    YYEncodingTypeQualifierBycopy = 1 << 12, ///< bycopy
    YYEncodingTypeQualifierByref  = 1 << 13, ///< byref
    YYEncodingTypeQualifierOneway = 1 << 14, ///< oneway
    
    YYEncodingTypePropertyMask         = 0xFF0000, ///< mask of property
    YYEncodingTypePropertyReadonly     = 1 << 16, ///< readonly
    YYEncodingTypePropertyCopy         = 1 << 17, ///< copy
    YYEncodingTypePropertyRetain       = 1 << 18, ///< retain
    YYEncodingTypePropertyNonatomic    = 1 << 19, ///< nonatomic
    YYEncodingTypePropertyWeak         = 1 << 20, ///< weak
    YYEncodingTypePropertyCustomGetter = 1 << 21, ///< getter=
    YYEncodingTypePropertyCustomSetter = 1 << 22, ///< setter=
    YYEncodingTypePropertyDynamic      = 1 << 23, ///< @dynamic
};

很明显了,最上面YYEncodingTypexxx 是代表变量的类型编码,YYEncodingTypeQualifierxxx 是代表类型修饰符编码,YYEncodingTypePropertyxxx 则是代表属性的 attributes 的编码。其中属性的 attributes 的编码处理在YYPropertyInfo初始化的时候就已经处理了,YYEncodingGetType 这个方法只是用来处理类型的编码。

上一篇下一篇

猜你喜欢

热点阅读