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 屬性信息
相關文章
相關標籤/搜索