iOS YYModel 源码 解析 (YYClassInfo.h)

YYEncodingType

/**
 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 }; 复制代码

@encode

Type Encodings 官方文档@encode 是一个编译器指令,返回类型内部表示的字符串 ,例:@encode(int) = i ,其做用就是能够加快运行时库的消息分发。html

附表:

Code Meaning
c char
i int
s short
l long
q long long
C unsigned char
I unsigned int
S unsigned short
L unsigned long
Q unsigned long long
f float
d double
B C++ bool or a C99 _Bool
v void
* character string (char *)
@ object (whether statically typed or typed id)
# class object (Class)
: method selector (SEL)
[array type] array
{name=type...} structure
(name=type...) union
bnum bit field of num bits
^type pointer to type
? unknown type (among other things, this code is used for function pointers)

备注:

  1. 指针的标准编码是加一个前置的 ^
  2. 由于 C 字符串被认为是一个实体,而不是指针。 char * 拥有本身的编码 *
  3. OC不支持 long double 类型,传入long double会和double同样返回d。。
  4. BOOLc ,而不是 i 。缘由是 Objective-C 设计之初每一个 bit 都比今天的要值钱, charint 占位小。BOOL 更确切地说是 signed char (即便设置了 -funsigned-char 参数),以在不一样编译器之间保持一致,由于 char 能够是 signed 或者 unsigned
  5. 直接传入 NSObject 会返回 {NSObject=#} 。可是传入 [NSObject class] 产生一个名为 NSObject 的只有一个类字段的结构体,就是实例变量 isa 。全部的 NSObject 实例都用它来表示本身的类型。
  6. 数组类型例:包含12个float型指针的数组会返回 [12^f]
  7. 结构体类型例:
    typedef struct example { id anObject; char *aString; int anInt; } Example;
    会返回
    {Example=@*i}
  8. 结构指针的编码包含与结构字段相同数量的信息,7. 中的结构体指针会返回^{Example=@*i}

YYEncodingGetType

YYEncodingType YYEncodingGetType(const char *typeEncoding);
复制代码

typeEncoding 转为 YYEncodingType 的方法,方便使用。数组


YYClassIvarInfo

/**
 Instance variable information.
 */
@interface YYClassIvarInfo : NSObject
@property (nonatomic, assign, readonly) Ivar ivar;              ///< ivar opaque struct
@property (nonatomic, strong, readonly) NSString *name;         ///< Ivar's name @property (nonatomic, assign, readonly) ptrdiff_t offset; ///< Ivar's offset
@property (nonatomic, strong, readonly) NSString *typeEncoding; ///< Ivar's type encoding @property (nonatomic, assign, readonly) YYEncodingType type; ///< Ivar's type

/**
 Creates and returns an ivar info object.
 
 @param ivar ivar opaque struct
 @return A new object, or nil if an error occurs.
 */
- (instancetype)initWithIvar:(Ivar)ivar;
@end
复制代码

YYClassIvarInfoobjc_ivar 结构体的封装缓存

先科普一下objc_ivar ,这是 Runtime 中表示变量的结构体bash

struct objc_ivar {
    char * _Nullable ivar_name OBJC2_UNAVAILABLE; // 名称
    char * _Nullable ivar_type OBJC2_UNAVAILABLE; // 类型
    int ivar_offset OBJC2_UNAVAILABLE; // 偏移字节
#ifdef __LP64__ // 若是已定义 __LP64__ 则表示正在构建 64 位目标
    int space OBJC2_UNAVAILABLE; // 变量空间
#endif
}
复制代码

说明以下:app

属性名 说明
ivar 变量,对应 objc_ivar
name 变量名称,对应 ivar_name
offset 变量偏移字节,对应 ivar_offset
typeEncoding 变量类型编码,经过 ivar_getTypeEncoding 函数获得
type(扩展) 变量类型,经过 YYEncodingGetType 方法从类型编码中获得

YYClassMethodInfo

/**
 Method information.
 */
@interface YYClassMethodInfo : NSObject
@property (nonatomic, assign, readonly) Method method;                  ///< method opaque struct
@property (nonatomic, strong, readonly) NSString *name;                 ///< method name
@property (nonatomic, assign, readonly) SEL sel;                        ///< method's selector @property (nonatomic, assign, readonly) IMP imp; ///< method's implementation
@property (nonatomic, strong, readonly) NSString *typeEncoding;         ///< method's parameter and return types @property (nonatomic, strong, readonly) NSString *returnTypeEncoding; ///< return value's type
@property (nullable, nonatomic, strong, readonly) NSArray<NSString *> *argumentTypeEncodings; ///< array of arguments' type /** Creates and returns a method info object. @param method method opaque struct @return A new object, or nil if an error occurs. */ - (instancetype)initWithMethod:(Method)method; @end 复制代码

YYClassMethodInfoobjc_method 结构体的封装ide

先科普一下 objc_method ,这是 Runtime 中定义方法的结构体函数

struct objc_method {
      SEL method_name; // 方法名
      char *method_types; // 方法类型
      IMP method_imp; // 函数指针(方法实现)
  } 
复制代码

神奇的是 method_name 类型是SEL~
SEL是方法选择器 selector 的简。运行时,发消息就是发送SEL,根据SEL找到地址,最后调用方法。ui

具体怎么找的不用关注,猜想有多是方法和方法名字符串的映射~this

说明以下:编码

属性名 说明
method 方法
name 方法名,对应method_name
sel 方法选择器
imp 函数指针(方法实现),对应 method_imp
typeEncoding 方法类型编码,对应 method_types
returnTypeEncoding 返回值类型编码
argumentTypeEncodings 参数类型编码,数组

YYClassPropertyInfo

/**
 Property information.
 */
@interface YYClassPropertyInfo : NSObject
@property (nonatomic, assign, readonly) objc_property_t property; ///< property's opaque struct @property (nonatomic, strong, readonly) NSString *name; ///< property's name
@property (nonatomic, assign, readonly) YYEncodingType type;      ///< property's type @property (nonatomic, strong, readonly) NSString *typeEncoding; ///< property's encoding value
@property (nonatomic, strong, readonly) NSString *ivarName;       ///< property's ivar name @property (nullable, nonatomic, assign, readonly) Class cls; ///< may be nil @property (nullable, nonatomic, strong, readonly) NSArray<NSString *> *protocols; ///< may nil @property (nonatomic, assign, readonly) SEL getter; ///< getter (nonnull) @property (nonatomic, assign, readonly) SEL setter; ///< setter (nonnull) /** Creates and returns a property info object. @param property property opaque struct @return A new object, or nil if an error occurs. */ - (instancetype)initWithProperty:(objc_property_t)property; @end 复制代码

YYClassPropertyInfo 是做者对 property_t 的封装,

先科普一下 property_t ,这是 Runtime 中表示属性的结构体。

struct property_t {
    const char *name; // 名称
    const char *attributes; // 修饰
};
复制代码

说明以下:

属性名 说明
property property_t 结构体
name 属性名,对应 name
type(扩展) 属性类型
typeEncoding(扩展) 属性类型编码
ivarName(扩展) 变量名称
protocols(扩展) 协议
getter(扩展) getter 方法选择器
setter(扩展) setter 方法选择器

YYClassInfo

/**
 Class information for a class.
 */
@interface YYClassInfo : NSObject
@property (nonatomic, assign, readonly) Class cls; ///< class object
@property (nullable, nonatomic, assign, readonly) Class superCls; ///< super class object
@property (nullable, nonatomic, assign, readonly) Class metaCls;  ///< class's meta class object @property (nonatomic, readonly) BOOL isMeta; ///< whether this class is meta class @property (nonatomic, strong, readonly) NSString *name; ///< class name @property (nullable, nonatomic, strong, readonly) YYClassInfo *superClassInfo; ///< super class's class info
@property (nullable, nonatomic, strong, readonly) NSDictionary<NSString *, YYClassIvarInfo *> *ivarInfos; ///< ivars
@property (nullable, nonatomic, strong, readonly) NSDictionary<NSString *, YYClassMethodInfo *> *methodInfos; ///< methods
@property (nullable, nonatomic, strong, readonly) NSDictionary<NSString *, YYClassPropertyInfo *> *propertyInfos; ///< properties

/**
 If the class is changed (for example: you add a method to this class with
 'class_addMethod()'), you should call this method to refresh the class info cache.
 
 After called this method, `needUpdate` will returns `YES`, and you should call 
 'classInfoWithClass' or 'classInfoWithClassName' to get the updated class info.
 */
- (void)setNeedUpdate;

/**
 If this method returns `YES`, you should stop using this instance and call
 `classInfoWithClass` or `classInfoWithClassName` to get the updated class info.
 
 @return Whether this class info need update.
 */
- (BOOL)needUpdate;

/**
 Get the class info of a specified Class.
 
 @discussion This method will cache the class info and super-class info
 at the first access to the Class. This method is thread-safe.
 
 @param cls A class.
 @return A class info, or nil if an error occurs.
 */
+ (nullable instancetype)classInfoWithClass:(Class)cls;

/**
 Get the class info of a specified Class.
 
 @discussion This method will cache the class info and super-class info
 at the first access to the Class. This method is thread-safe.
 
 @param className A class name.
 @return A class info, or nil if an error occurs.
 */
+ (nullable instancetype)classInfoWithClassName:(NSString *)className;
复制代码

YYClassInfo 是做者对 objc_class 的封装,

先科普一下 objc_class ,这是 Runtime 中表示类的结构体。

typedef struct objc_class *Class;

// runtime.h
struct objc_class {
    Class _Nonnull isa OBJC_ISA_AVAILABILITY; // isa 指针

#if !__OBJC2__
    Class _Nullable super_class OBJC2_UNAVAILABLE; // 父类指针
    const char * _Nonnull name OBJC2_UNAVAILABLE; // 类名
    long version OBJC2_UNAVAILABLE; // 版本
    long info OBJC2_UNAVAILABLE; // 信息
    long instance_size OBJC2_UNAVAILABLE; // 空间大小
    struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE; // 变量列表
    struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE; // 方法列表
    struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE; // 缓存
    struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE; // 协议列表
#endif

} OBJC2_UNAVAILABLE;
复制代码

说明以下:

属性名 说明
cls
superCls 父类
metaCls 元类
isMeta 自身是否元类
name 类名
superClassInfo 父类的信息
ivarInfos 变量信息
methodInfos 方法信息
propertyInfos 属性信息
相关文章
相关标签/搜索