Ivar
Ivar
是一種代表類(lèi)中實(shí)例變量的類(lèi)型错沃。
typedef struct ivar_t *Ivar;
而 ivar_t
在上面的成員變量列表中也提到過(guò):
struct ivar_t {
int32_t *offset;
const char *name;
const char *type;
// alignment is sometimes -1; use alignment() instead
uint32_t alignment_raw;
uint32_t size;
uint32_t alignment() const {
if (alignment_raw == ~(uint32_t)0) return 1U << WORD_SHIFT;
return 1 << alignment_raw;
}
};
可以根據(jù)實(shí)例查找其在類(lèi)中的名字,也就是“反射”:
-(NSString *)nameWithInstance:(id)instance {
unsigned int numIvars = 0;
NSString *key=nil;
Ivar * ivars = class_copyIvarList([self class], &numIvars);
for(int i = 0; i < numIvars; i++) {
Ivar thisIvar = ivars[i];
const char *type = ivar_getTypeEncoding(thisIvar);
NSString *stringType = [NSString stringWithCString:type encoding:NSUTF8StringEncoding];
if (![stringType hasPrefix:@"@"]) {
continue;
}
if ((object_getIvar(self, thisIvar) == instance)) {//此處若 crash 不要慌秋茫!
key = [NSString stringWithUTF8String:ivar_getName(thisIvar)];
break;
}
}
free(ivars);
return key;
}
class_copyIvarList
函數(shù)獲取的不僅有實(shí)例變量胡诗,還有屬性燕锥。但會(huì)在原本的屬性名前加上一個(gè)下劃線(xiàn)子刮。
objc_property_t
@property
標(biāo)記了類(lèi)中的屬性客叉,這個(gè)不必多說(shuō)大家都很熟悉,它是一個(gè)指向objc_property
結(jié)構(gòu)體的指針:
typedef struct property_t *objc_property_t;
可以通過(guò) class_copyPropertyList 和 protocol_copyPropertyList 方法來(lái)獲取類(lèi)和協(xié)議中的屬性:
objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)
objc_property_t *protocol_copyPropertyList(Protocol *proto, unsigned int *outCount)
返回類(lèi)型為指向指針的指針话告,哈哈,因?yàn)閷傩粤斜硎莻€(gè)數(shù)組卵慰,每個(gè)元素內(nèi)容都是一個(gè) objc_property_t 指針沙郭,而這兩個(gè)函數(shù)返回的值是指向這個(gè)數(shù)組的指針。
舉個(gè)栗子裳朋,先聲明一個(gè)類(lèi):
@interface Lender : NSObject {
float alone;
}
@property float alone;
@end
你可以用下面的代碼獲取屬性列表:
id LenderClass = objc_getClass("Lender");
unsigned int outCount;
objc_property_t *properties = class_copyPropertyList(LenderClass, &outCount);
你可以用 property_getName
函數(shù)來(lái)查找屬性名稱(chēng):
const char *property_getName(objc_property_t property)
你可以用class_getProperty 和 protocol_getProperty通過(guò)給出的名稱(chēng)來(lái)在類(lèi)和協(xié)議中獲取屬性的引用:
objc_property_t class_getProperty(Class cls, const char *name)
objc_property_t protocol_getProperty(Protocol *proto, const char *name, BOOL isRequiredProperty, BOOL isInstanceProperty)
你可以用property_getAttributes函數(shù)來(lái)發(fā)掘?qū)傩缘拿Q(chēng)和@encode類(lèi)型字符串:
const char *property_getAttributes(objc_property_t property)
把上面的代碼放一起病线,你就能從一個(gè)類(lèi)中獲取它的屬性啦:
id LenderClass = objc_getClass("Lender");
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList(LenderClass, &outCount);
for (i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
fprintf(stdout, "%s %s\n", property_getName(property), property_getAttributes(property));
}
對(duì)比下class_copyIvarList
函數(shù),使用 class_copyPropertyList
函數(shù)只能獲取類(lèi)的屬性鲤嫡,而不包含成員變量送挑。但此時(shí)獲取的屬性名是不帶下劃線(xiàn)的。
protocol_t
雖然 Objective-C
的 Category
和 protocol
拓展能力有限暖眼,但也得為了將就 Swift 的感受惕耕,充個(gè)胖子。
flags 32 位指針最后兩位是給加載 Mach-O 的 fix-up 階段使用的诫肠,前 16 位預(yù)留給 Swift 用的司澎。
protocol 主要內(nèi)容其實(shí)是(可選)方法,其次就是繼承其他 protocol栋豫。Swift 還支持 protocol 多繼承挤安,所以需要 protocols 數(shù)組來(lái)做兼容。
struct protocol_t : objc_object {
const char *mangledName;
struct protocol_list_t *protocols;
method_list_t *instanceMethods;
method_list_t *classMethods;
method_list_t *optionalInstanceMethods;
method_list_t *optionalClassMethods;
property_list_t *instanceProperties;
uint32_t size; // sizeof(protocol_t)
uint32_t flags;
// Fields below this point are not always present on disk.
const char **_extendedMethodTypes;
const char *_demangledName;
property_list_t *_classProperties;
... 省略一些封裝的便捷 get 方法
}
IMP
IMP在objc.h中的定義是:
typedef void (*IMP)(void /* id, SEL, ... */ );
它就是一個(gè)函數(shù)指針丧鸯,這是由編譯器生成的蛤铜。當(dāng)你發(fā)起一個(gè) ObjC 消息之后,最終它會(huì)執(zhí)行的那段代碼丛肢,就是由這個(gè)函數(shù)指針指定的围肥。而 IMP
這個(gè)函數(shù)指針就指向了這個(gè)方法的實(shí)現(xiàn)。既然得到了執(zhí)行某個(gè)實(shí)例某個(gè)方法的入口蜂怎,我們就可以繞開(kāi)消息傳遞階段虐先,直接執(zhí)行方法,這在后面會(huì)提到派敷。
你會(huì)發(fā)現(xiàn) IMP 指向的方法與 objc_msgSend 函數(shù)類(lèi)型相同蛹批,參數(shù)都包含 id 和 SEL 類(lèi)型撰洗。每個(gè)方法名都對(duì)應(yīng)一個(gè) SEL 類(lèi)型的方法選擇器,而每個(gè)實(shí)例對(duì)象中的 SEL 對(duì)應(yīng)的方法實(shí)現(xiàn)肯定是唯一的腐芍,通過(guò)一組 id 和 SEL 參數(shù)就能確定唯一的方法實(shí)現(xiàn)地址差导;反之亦然。