Objective-C中的meta-class

討論Objective-C的一個(gè)奇怪的概念 meta-class

在Objective-C中的每個(gè)類杖狼,都有它自己相關(guān)的meta-class掌腰,但因?yàn)槟愫苌僦苯邮褂胢eta-class,所以顯得很神秘冒窍。

在運(yùn)行時(shí)建立一個(gè)類

下面的代碼在運(yùn)行時(shí)創(chuàng)建一個(gè)NSError新的子類俯树,并添加一個(gè)方法到里面:

Class newClass =

objc_allocateClassPair([NSError class], “RuntimeErrorSubclass”, 0);

class_addMethod(newClass, @selector(report), (IMP)ReportFunction, “v@:”);

objc_registerClassPair(newClass);

添加的這個(gè)方法用ReportFunction函數(shù)名作為它的實(shí)現(xiàn)闰歪,實(shí)現(xiàn)定義在下面

void ReportFunction(id self, SEL _cmd)

{

NSLog(@”This object is %p.”, self);

NSLog(@”Class is %@, and super is %@.”, [self class], [self superclass]);

Class currentClass = [self class];

for (int i = 1; i < 5; i++)

{

NSLog(@”Following the isa pointer %d times gives %p”, i, currentClass);

currentClass = object_getClass(currentClass);

}

NSLog(@”NSObject’s class is %p”, [NSObject class]);

NSLog(@”NSObject’s meta class is %p”, object_getClass([NSObject class]));

}

表面上榛泛,這都很簡(jiǎn)單蝌蹂。在運(yùn)行時(shí)創(chuàng)建一個(gè)新類,只需要3步

1)為 class pair分配存儲(chǔ)空間 (使用objc_allocateClassPair)

2)增加需要的方法和ivars(使用class_addMethod來添加方法)

3) 注冊(cè)這個(gè)類曹锨,以便它能被別人使用(objc_registerClassPair)

現(xiàn)在的問題是孤个,什么是class pair, 函數(shù)objc_allocateClassPair只返回一個(gè)值:the class

那么pair的另外一半在哪里呢?你可能已經(jīng)猜到另外一般就是meta-class(也就是本文的主題)

一個(gè)數(shù)據(jù)結(jié)構(gòu)需要哪些東西才能成為一個(gè)對(duì)象

每個(gè)對(duì)象都有一個(gè)類沛简,這是一個(gè)基本的面向?qū)ο蟮母拍睢?/p>

在Objective-C中齐鲤,任何數(shù)據(jù)結(jié)構(gòu),如果在正確的位置有一個(gè)指向類的指針椒楣,就能被視為一個(gè)對(duì)象给郊。

在Objective-C中,一個(gè)對(duì)象的類捧灰,由它的isa指針決定淆九。這個(gè)isa指針指向 對(duì)象的類。

事實(shí)上凤壁,一個(gè)對(duì)象的基本定義是這樣的:

typedef struct objc_object {

Class isa;

} *id;

這就是說吩屹,任何以一個(gè)指向Class結(jié)構(gòu)的指針開始的結(jié)構(gòu),都能被當(dāng)作objc_object

對(duì)象最重要的特性拧抖,就是你可以給它們發(fā)送消息:

[@"stringValue"

writeToFile:@"/file.txt" atomically:YES encoding:NSUTF8StringEncoding error:NULL];

當(dāng)你發(fā)送消息給一個(gè)Objective-C對(duì)象時(shí)(比如這里的NSCFString), 運(yùn)行時(shí)(runtime) 通過對(duì)象的isa指針得到對(duì)象的Class(這里是NSCFString類)煤搜,而Class里含有那些可以應(yīng)用這個(gè)類的所有對(duì)象上的所有方法的列表,以及指向superclass的指針唧席。運(yùn)行時(shí)通過類的方法列表和超類擦盾,來發(fā)現(xiàn)一個(gè)能同消息選擇子匹配的方法(上面的例子中,就是在NSString類中的writeToFile:atomically:encoding:error方法)淌哟。

要點(diǎn)就是:類定義了那些消息迹卢,你只能發(fā)送那些已經(jīng)定義好的消息給它的對(duì)象

什么是meta-class

現(xiàn)在,你可能已經(jīng)知道徒仓,在Objective-C中腐碱,一個(gè)類也是一個(gè)對(duì)象。這意味著,你也可以發(fā)送消息給一個(gè)類

NSStringEncoding defaultStringEncoding = [NSString defaultStringEncoding];

在這種情況下症见, defaultStringEncoding被發(fā)送給NSString類

在Objective-C 中喂走,每個(gè)類,都是一個(gè)對(duì)象谋作。也就是說芋肠,類結(jié)構(gòu)也必須以isa指針開始,這樣遵蚜,它才同objc_object結(jié)構(gòu)二進(jìn)制兼容

在結(jié)構(gòu)里的第2個(gè)項(xiàng)目帖池,必須是superclass的指針(如果是基類,沒有父類的話吭净,設(shè)置為nil)

定義一個(gè)類睡汹,有很多不同的方式,依賴于你的運(yùn)行時(shí)版本而不同攒钳,但他們都以 isa開始帮孔,然后后面接著superclass

typedef struct objc_class *Class;

struct objc_class {

Class isa;

Class super_class;

/* followed by runtime specific details… */

};

為了讓我們調(diào)用類的一個(gè)方法雷滋,類的isa指針必須指向一個(gè)類結(jié)構(gòu)不撑,并且,類結(jié)構(gòu)必須含有我們能在該類上調(diào)用的方法列表

這就導(dǎo)致了一個(gè)meta-class的定義:meta-class是一個(gè)類對(duì)象的類

簡(jiǎn)單地說晤斩,

當(dāng)你發(fā)送一條消息給一個(gè)對(duì)象時(shí)焕檬,這條消息會(huì)在對(duì)象的類的方法列表里查找

當(dāng)你發(fā)送一條消息給一個(gè)類時(shí),就會(huì)在類的meta-class的方法列表理查找消息

meta-class是必不可少的澳泵,因?yàn)樗鎯?chǔ)了一個(gè)類的類 方法实愚。每個(gè)類都必須只有唯一的meta-class,因?yàn)槊總€(gè)類都只可能有一個(gè)唯一的類方法列表。

meta-class的類又是什么呢兔辅?

meta-class腊敲,跟 類一樣,它也是一個(gè)對(duì)象维苔。這意味著碰辅,你也可以在它上面調(diào)用方法。自然地介时,這意味這没宾,它也必須有一個(gè)類。

所有的meta-class都使用基類的meta-class(在它們的繼承體系中沸柔,最頂層的類的meta-class)作為它們自己的類循衰。這意味著,所有從NSObject繼承來的類褐澎,它們的meta-class都將NSObject的meta-class作為自己的類

遵循這個(gè)規(guī)則会钝,所有的meta-class使用基類的meta-class作為它們自己的類,任何base meta-class都將是它自己的類(它們的isa指針指向它們自己)工三。也就是說迁酸,在 NSObject的meta-class的isa指針將指向它自己(它是自己的一個(gè)實(shí)例)

類和 meta-class的繼承

同樣的方式咽弦,類用super_class 指針指向超類,meta-class使用它自己的super_class指向 類的super-class的meta-class

巧合地是胁出,基類的meta-class設(shè)置它的 super_class 為基類自己型型。

用實(shí)驗(yàn)來驗(yàn)證我們的想法

為了確認(rèn)這些情況,我們看看ReportFunctional的輸出全蝶。 這個(gè)函數(shù)的目的是 追蹤isa指針闹蒜,并記錄在哪里找到的它。

為了運(yùn)行ReportFunction抑淫,我們需要建立這個(gè)動(dòng)態(tài)創(chuàng)建的類的實(shí)例绷落,然后調(diào)用它的report方法

id instanceOfNewClass =

[[newClass alloc] initWithDomain:@”someDomain” code:0 userInfo:nil];

[instanceOfNewClass performSelector:@selector(report)];

[instanceOfNewClass release];

因?yàn)闆]有report方法的聲明,我使用performSelector:來調(diào)用它始苇,所以編譯不會(huì)給出什么警告

ReportFunction將遍歷isa指針砌烁,告訴我們那些對(duì)象被當(dāng)成類,meta-class催式,以及meta-class的類 來使用

取得一個(gè)對(duì)象的類:ReportFunction將使用object_getClass來追蹤isa指針函喉, 因?yàn)閕sa指針是類的一個(gè)被保護(hù)的成員(你不能直接訪問其他類的isa指針)

ReportFunction不使用類方法來實(shí)現(xiàn)這個(gè),因?yàn)檎{(diào)用一個(gè)類對(duì)象的類方法荣月,將不會(huì)返回meta-class. 而是再次返回這個(gè)類(所以[NSString class]將返回NSString類管呵,而不是NSString的meta-class)

結(jié)論:

meta-class是類對(duì)象的類。每個(gè)類都有它自己唯一的meta-class(因?yàn)槊總€(gè)類都有它自己唯一的方法列表)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末哺窄,一起剝皮案震驚了整個(gè)濱河市捐下,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌萌业,老刑警劉巖坷襟,帶你破解...
    沈念sama閱讀 222,627評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異生年,居然都是意外死亡婴程,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門晶框,熙熙樓的掌柜王于貴愁眉苦臉地迎上來排抬,“玉大人,你說我怎么就攤上這事授段《灼眩” “怎么了?”我有些...
    開封第一講書人閱讀 169,346評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵侵贵,是天一觀的道長(zhǎng)届搁。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么卡睦? 我笑而不...
    開封第一講書人閱讀 60,097評(píng)論 1 300
  • 正文 為了忘掉前任宴胧,我火速辦了婚禮,結(jié)果婚禮上表锻,老公的妹妹穿的比我還像新娘恕齐。我一直安慰自己,他們只是感情好瞬逊,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評(píng)論 6 398
  • 文/花漫 我一把揭開白布显歧。 她就那樣靜靜地躺著,像睡著了一般确镊。 火紅的嫁衣襯著肌膚如雪士骤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,696評(píng)論 1 312
  • 那天蕾域,我揣著相機(jī)與錄音拷肌,去河邊找鬼。 笑死旨巷,一個(gè)胖子當(dāng)著我的面吹牛巨缘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播契沫,決...
    沈念sama閱讀 41,165評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼带猴,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了懈万?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,108評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤靶病,失蹤者是張志新(化名)和其女友劉穎会通,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體娄周,經(jīng)...
    沈念sama閱讀 46,646評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡涕侈,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了煤辨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片裳涛。...
    茶點(diǎn)故事閱讀 40,861評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖众辨,靈堂內(nèi)的尸體忽然破棺而出端三,到底是詐尸還是另有隱情,我是刑警寧澤鹃彻,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布郊闯,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏团赁。R本人自食惡果不足惜育拨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望欢摄。 院中可真熱鬧熬丧,春花似錦、人聲如沸怀挠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽唆香。三九已至嫌变,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間躬它,已是汗流浹背腾啥。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留冯吓,地道東北人倘待。 一個(gè)月前我還...
    沈念sama閱讀 49,287評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像组贺,于是被迫代替她去往敵國(guó)和親凸舵。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容