Objective-C runtime(二)

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-CCategoryprotocol 拓展能力有限暖眼,但也得為了將就 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)地址差导;反之亦然。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末猪勇,一起剝皮案震驚了整個(gè)濱河市设褐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌泣刹,老刑警劉巖助析,帶你破解...
    沈念sama閱讀 221,888評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異椅您,居然都是意外死亡外冀,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)掀泳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)雪隧,“玉大人,你說(shuō)我怎么就攤上這事员舵∧匝兀” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,386評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵马僻,是天一觀的道長(zhǎng)庄拇。 經(jīng)常有香客問(wèn)我,道長(zhǎng)韭邓,這世上最難降的妖魔是什么丛忆? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,726評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮仍秤,結(jié)果婚禮上熄诡,老公的妹妹穿的比我還像新娘。我一直安慰自己诗力,他們只是感情好凰浮,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,729評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著苇本,像睡著了一般袜茧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上瓣窄,一...
    開(kāi)封第一講書(shū)人閱讀 52,337評(píng)論 1 310
  • 那天笛厦,我揣著相機(jī)與錄音,去河邊找鬼俺夕。 笑死裳凸,一個(gè)胖子當(dāng)著我的面吹牛贱鄙,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播姨谷,決...
    沈念sama閱讀 40,902評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼逗宁,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了梦湘?” 一聲冷哼從身側(cè)響起瞎颗,我...
    開(kāi)封第一講書(shū)人閱讀 39,807評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎捌议,沒(méi)想到半個(gè)月后哼拔,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,349評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瓣颅,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,439評(píng)論 3 340
  • 正文 我和宋清朗相戀三年倦逐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弄捕。...
    茶點(diǎn)故事閱讀 40,567評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖导帝,靈堂內(nèi)的尸體忽然破棺而出守谓,到底是詐尸還是另有隱情,我是刑警寧澤您单,帶...
    沈念sama閱讀 36,242評(píng)論 5 350
  • 正文 年R本政府宣布斋荞,位于F島的核電站,受9級(jí)特大地震影響虐秦,放射性物質(zhì)發(fā)生泄漏平酿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,933評(píng)論 3 334
  • 文/蒙蒙 一悦陋、第九天 我趴在偏房一處隱蔽的房頂上張望蜈彼。 院中可真熱鬧,春花似錦俺驶、人聲如沸幸逆。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,420評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)还绘。三九已至,卻和暖如春栖袋,著一層夾襖步出監(jiān)牢的瞬間拍顷,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,531評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工塘幅, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留昔案,地道東北人尿贫。 一個(gè)月前我還...
    沈念sama閱讀 48,995評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像爱沟,于是被迫代替她去往敵國(guó)和親帅霜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,585評(píng)論 2 359