Objective-C runtime(二)

Ivar

Ivar 是一種代表類中實例變量的類型。

typedef struct ivar_t *Ivar;

ivar_t在上面的成員變量列表中也提到過:

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ù)實例查找其在類中的名字,也就是“反射”:

-(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ù)獲取的不僅有實例變量,還有屬性。但會在原本的屬性名前加上一個下劃線。

objc_property_t

@property標記了類中的屬性,這個不必多說大家都很熟悉,它是一個指向objc_property結(jié)構(gòu)體的指針:


typedef struct property_t *objc_property_t;

可以通過 class_copyPropertyList 和 protocol_copyPropertyList 方法來獲取類和協(xié)議中的屬性:

objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)
objc_property_t *protocol_copyPropertyList(Protocol *proto, unsigned int *outCount)

返回類型為指向指針的指針,哈哈,因為屬性列表是個數(shù)組,每個元素內(nèi)容都是一個 objc_property_t 指針,而這兩個函數(shù)返回的值是指向這個數(shù)組的指針。

舉個栗子,先聲明一個類:

@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ù)來查找屬性名稱:

const char *property_getName(objc_property_t property)

你可以用class_getProperty 和 protocol_getProperty通過給出的名稱來在類和協(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ù)來發(fā)掘?qū)傩缘拿Q和@encode類型字符串:

const char *property_getAttributes(objc_property_t property)

把上面的代碼放一起,你就能從一個類中獲取它的屬性啦:

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));
}

對比下class_copyIvarList 函數(shù),使用 class_copyPropertyList 函數(shù)只能獲取類的屬性,而不包含成員變量。但此時獲取的屬性名是不帶下劃線的。

protocol_t

雖然 Objective-CCategoryprotocol 拓展能力有限,但也得為了將就 Swift 的感受,充個胖子。
flags 32 位指針最后兩位是給加載 Mach-O 的 fix-up 階段使用的,前 16 位預留給 Swift 用的。
protocol 主要內(nèi)容其實是(可選)方法,其次就是繼承其他 protocol。Swift 還支持 protocol 多繼承,所以需要 protocols 數(shù)組來做兼容。

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, ... */ );

它就是一個函數(shù)指針,這是由編譯器生成的。當你發(fā)起一個 ObjC 消息之后,最終它會執(zhí)行的那段代碼,就是由這個函數(shù)指針指定的。而 IMP這個函數(shù)指針就指向了這個方法的實現(xiàn)。既然得到了執(zhí)行某個實例某個方法的入口,我們就可以繞開消息傳遞階段,直接執(zhí)行方法,這在后面會提到。

你會發(fā)現(xiàn) IMP 指向的方法與 objc_msgSend 函數(shù)類型相同,參數(shù)都包含 id 和 SEL 類型。每個方法名都對應一個 SEL 類型的方法選擇器,而每個實例對象中的 SEL 對應的方法實現(xiàn)肯定是唯一的,通過一組 id 和 SEL 參數(shù)就能確定唯一的方法實現(xiàn)地址;反之亦然。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容