YYModel源码阅读(2)

我们来分析YYClassInfo这个类,一开始,作者写了3种编码

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
   //1.自定义类型 2.NSObject
    YYEncodingTypeObject     = 14, ///< id
   //Class类型
    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)
  //取得8~16位的值类型:方法类型
    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
  //取得16~24位的值类型:属性的附加修饰类型
    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
};

这里分别有3个Mask,分别是YYEncodingTypeMask,YYEncodingTypeQualifierMask,YYEncodingTypePropertyMask
这个有什么用呢,我们来看个例子就知道了

typedef NS_OPTIONS(NSUInteger, JJEncodingType) {
    JJEncodingTypeMask = 0xFF,
    JJEncodingType1 = 1,
    JJEncodingType2 = 2,
    JJEncodingType3 = 3,
    
    JJEncodingTypeQualifireMask = 0xFF00,
    JJEncodingTypeQualifire1 = 1 << 8,
    JJEncodingTypeQualifire2 = 1 << 9,
    JJEncodingTypeQualifire3 = 1 << 10,
};
NSLog(@"JJEncodingType1 %d JJEncodingTypeQualifire2 %d",(int)JJEncodingType1,(int)JJEncodingTypeQualifire2);
    JJEncodingType test = (JJEncodingType1|JJEncodingTypeQualifire2);
    NSLog(@"%d",(int) test);
    NSLog(@"JJEncodingTypeMask %d, JJEncodingTypeQualifireMask %d",(int)(test&JJEncodingTypeMask), (int)(test&JJEncodingTypeQualifireMask));

打印的结果

 JJEncodingType1 1 JJEncodingTypeQualifire2 512
 513
 JJEncodingTypeMask 1, JJEncodingTypeQualifireMask 512

这就很明显了,如果有个属性分别具有JJEncodingType1和JJEncodingTypeQualifire2 的属性,我们可以通过Mask取出来,

然后是获取类型的方法,

//获取Type的 encode 返回枚举的YYEncodingType类型
YYEncodingType YYEncodingGetType(const char *typeEncoding) {
    //转换const char 为char
    char *type = (char *)typeEncoding;
    //如果获取不到type或者type长度<1 则返回未知类型
    if (!type) return YYEncodingTypeUnknown;
    size_t len = strlen(type);
    if (len == 0) return YYEncodingTypeUnknown;
    
    //用qulifier来确定当前type的encode
    YYEncodingType qualifier = 0;
    bool prefix = true;
    //判断method的类型,如果有就type指针+1,判断下一个字符,如果没有则跳出循环
    while (prefix) {
        switch (*type) {
            case 'r': {
                qualifier |= YYEncodingTypeQualifierConst;
                type++;
            } break;
            case 'n': {
                qualifier |= YYEncodingTypeQualifierIn;
                type++;
            } break;
            case 'N': {
                qualifier |= YYEncodingTypeQualifierInout;
                type++;
            } break;
            case 'o': {
                qualifier |= YYEncodingTypeQualifierOut;
                type++;
            } break;
            case 'O': {
                qualifier |= YYEncodingTypeQualifierBycopy;
                type++;
            } break;
            case 'R': {
                qualifier |= YYEncodingTypeQualifierByref;
                type++;
            } break;
            case 'V': {
                qualifier |= YYEncodingTypeQualifierOneway;
                type++;
            } break;
            default: { prefix = false; } break;
        }
    }
    //获取变化后的type长度
    len = strlen(type);
    //再一次判断是否为未知类型
    if (len == 0) return YYEncodingTypeUnknown | qualifier;
    //判断变量的类型
    switch (*type) {
        case 'v': return YYEncodingTypeVoid | qualifier;
        case 'B': return YYEncodingTypeBool | qualifier;
        case 'c': return YYEncodingTypeInt8 | qualifier;
        case 'C': return YYEncodingTypeUInt8 | qualifier;
        case 's': return YYEncodingTypeInt16 | qualifier;
        case 'S': return YYEncodingTypeUInt16 | qualifier;
        case 'i': return YYEncodingTypeInt32 | qualifier;
        case 'I': return YYEncodingTypeUInt32 | qualifier;
        case 'l': return YYEncodingTypeInt32 | qualifier;
        case 'L': return YYEncodingTypeUInt32 | qualifier;
        case 'q': return YYEncodingTypeInt64 | qualifier;
        case 'Q': return YYEncodingTypeUInt64 | qualifier;
        case 'f': return YYEncodingTypeFloat | qualifier;
        case 'd': return YYEncodingTypeDouble | qualifier;
        case 'D': return YYEncodingTypeLongDouble | qualifier;
        case '#': return YYEncodingTypeClass | qualifier;
        case ':': return YYEncodingTypeSEL | qualifier;
        case '*': return YYEncodingTypeCString | qualifier;
        case '^': return YYEncodingTypePointer | qualifier;
        case '[': return YYEncodingTypeCArray | qualifier;
        case '(': return YYEncodingTypeUnion | qualifier;
        case '{': return YYEncodingTypeStruct | qualifier;
        case '@': {
            if (len == 2 && *(type + 1) == '?')
                return YYEncodingTypeBlock | qualifier;
            else
                return YYEncodingTypeObject | qualifier;
        }
        default: return YYEncodingTypeUnknown | qualifier;
    }
}

知道了如何进行键值编码,我们继续来看YYClassInfo的组成
分别为YYClassIvarInfo,YYClassMethodInfo,YYClassPropertyInfo

@interface YYClassIvarInfo : NSObject
@property (nonatomic, assign, readonly) Ivar ivar;              ///< ivar
@property (nonatomic, strong, readonly) NSString *name;         ///< 成员变量名
@property (nonatomic, assign, readonly) ptrdiff_t offset;       ///< 变量的偏移地址
@property (nonatomic, strong, readonly) NSString *typeEncoding; ///< 变量的编码类型
@property (nonatomic, assign, readonly) YYEncodingType type;    ///< 转成YYType类型
//通过一个ivar填充YYClassIvarInfo
- (instancetype)initWithIvar:(Ivar)ivar;
@end

@implementation YYClassIvarInfo

- (instancetype)initWithIvar:(Ivar)ivar {
    //判断是否为一个合法的ivar
    if (!ivar) return nil;
    self = [super init];
    _ivar = ivar;
    //获取ivar的名称
    const char *name = ivar_getName(ivar);
    if (name) { //转化const char 属性为NSString
        _name = [NSString stringWithUTF8String:name];
    }
    //取得相对偏移量,这样做可以提高获取效率
    _offset = ivar_getOffset(ivar);
    const char *typeEncoding = ivar_getTypeEncoding(ivar);
    if (typeEncoding) {  //获取编码并转为YYType
        _typeEncoding = [NSString stringWithUTF8String:typeEncoding];
        _type = YYEncodingGetType(typeEncoding);
    }
    return self;
}
@end
@interface YYClassMethodInfo : NSObject
@property (nonatomic, assign, readonly) Method method;                  ///< 方法
@property (nonatomic, strong, readonly) NSString *name;                 ///< �方法名
@property (nonatomic, assign, readonly) SEL sel;                        ///< sel:方法选择器
@property (nonatomic, assign, readonly) IMP imp;                        ///< 方法实现
@property (nonatomic, strong, readonly) NSString *typeEncoding;         ///< 方法的编码
@property (nonatomic, strong, readonly) NSString *returnTypeEncoding;   ///< 返回值的类型
@property (nullable, nonatomic, strong, readonly) NSArray *argumentTypeEncodings; ///< 方法参数的编码
//通过一个方法填充YYClassMethodInfo
- (instancetype)initWithMethod:(Method)method;
@end
属性的描述信息
@interface YYClassPropertyInfo : NSObject
@property (nonatomic, assign, readonly) objc_property_t property; ///< property
@property (nonatomic, strong, readonly) NSString *name;           ///< 属性名
@property (nonatomic, assign, readonly) YYEncodingType type;      ///< 属性类型
@property (nonatomic, strong, readonly) NSString *typeEncoding;   ///< 属性编码
@property (nonatomic, strong, readonly) NSString *ivarName;       ///< �属性对应的ivar名字
@property (nullable, nonatomic, assign, readonly) Class cls;      ///< 属性的class
@property (nullable, nonatomic, strong, readonly) NSArray *protocols; ///< 属性的协议簇
@property (nonatomic, assign, readonly) SEL getter;               ///< getter (nonnull)
@property (nonatomic, assign, readonly) SEL setter;               ///< setter (nonnull)

//用属性填充YYClassPropertyInfo
- (instancetype)initWithProperty:(objc_property_t)property;
@end

暂时写到这里....发现要去恶补c++,所以等有空再更..

你可能感兴趣的:(YYModel源码阅读(2))