元類(meta class)

元類(meta class)茬腿,這個(gè)名字想必很多人都聽過聚至,網(wǎng)上也有很多關(guān)于元類的介紹慧瘤,今天我就按照自己這兩天的理解來簡單探討一下這個(gè)玩意戴已,有誤之處還望指出固该。

首先,下載objc源碼糖儡,源碼地址:https://opensource.apple.com/tarballs/objc4/
打開鏈接后會發(fā)現(xiàn)有很多版本伐坏,我直接下載的最新版(709版本)

認(rèn)識NSObject

1.打開objc工程的NSObject.h,找到NSObject類的定義
@interface NSObject <NSObject> {
    Class isa  OBJC_ISA_AVAILABILITY;  //發(fā)現(xiàn)NSObject包含一個(gè)Class對象
}

2.繼續(xù)查看Class類型
typedef struct objc_class *Class;

3.繼續(xù)查看objc_class類型
struct objc_class : objc_object {  //objc_class繼承自objc_object
    Class superclass;
    const char *name;
    uint32_t version;
    uint32_t info;
    ...
}

4.查看objc_object類型
struct objc_object {
private:
    isa_t isa;  //這個(gè)東西好像很牛逼握联,繼續(xù)看一下
    ...
}

5.查看isa_t類型
union isa_t 
{
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;    //誒桦沉,這個(gè)東西又出現(xiàn)了
    uintptr_t bits;
}

簡單用圖片表示一下:


圖-1

那么簡單總結(jié)一下就是,NSObject包含一個(gè)Class金闽,Class中包含一個(gè)superclass和cls

meta class 獲取

1.打開objc工程的runtime.h纯露,找到meta class的獲取接口
Class objc_getMetaClass(const char *name) {
    //下面代碼進(jìn)行了簡化
    //1.通過類名找到類對象(注意不是類實(shí)例對象)
    Class cls = objc_getClass (aClassName);
    //2.返回上面圖-1中最里面的cls
    return cls->isa.cls;
}

2.meta class的獲取其實(shí)就是獲取類對象包含的cls,而我們在實(shí)際開發(fā)中是不能調(diào)用到cls的代芜,這時(shí)埠褪,可以通過object_getClass來實(shí)現(xiàn)。
查看object_getClass的實(shí)現(xiàn)
Class object_getClass(id obj) {
    //下面代碼經(jīng)過簡化
    return obj->isa.cls;  //也是返回cls
}

通過測試代碼來分析源碼

//引入rumtime頭文件
#import <objc/objc-runtime.h>
//定義一個(gè)簡單的類
@interface Father : NSObject
@property (nonatomic, strong) NSString *name;
@end
//各種實(shí)例打印
    Father* f = [[Father alloc] init];
    
    NSLog(@"f address:%p", f);
    NSLog(@"[f class] address:%p", [f class]);
    NSLog(@"[Father class] address:%p", [Father class]);
    NSLog(@"objc_getMetaClass address:%p", objc_getMetaClass("Father"));
    NSLog(@"objc_getClass address:%p", object_getClass([Father class]));

打印結(jié)果:

打印結(jié)果:
2017-04-26 11:46:37.104 runtimeDemo[190:22480332] f address:0x600000011e70
2017-04-26 11:46:37.104 runtimeDemo[190:22480332] [f class] address:0x1063d5ff0
2017-04-26 11:46:37.105 runtimeDemo[190:22480332] [Father class] address:0x1063d5ff0
2017-04-26 11:46:37.105 runtimeDemo[190:22480332] objc_getMetaClass address:0x1063d5fc8
2017-04-26 11:46:37.105 runtimeDemo[190:22480332] objc_getClass address:0x1063d5fc8

通過結(jié)果進(jìn)行分析:

  • 類實(shí)例對象本身不是元類
  • 類實(shí)例對象通過class方法獲取到的對象為類對象挤庇,[f class] == [Father class]
  • 通過類對象調(diào)用的object_getClass得到的是meta class

meta class 繼承

meta class繼承圖

這是一張很牛逼的圖钞速,我們用盡量簡單的代碼來測試一下:

    Son *s = [[Son alloc] init];    //Instance of Subclass
    Class cls = [s class];     //Subclass class
    Class meta = object_getClass(cls);  //Subclass meta
    
    Class superclass = [cls superclass];
    Class supermeta = [meta superclass];
    Class supermeta2 = object_getClass(superclass);
    
    Class rootclass = [superclass superclass];
    Class rootmeta = [supermeta superclass];
    Class rootmeta2 = object_getClass(rootclass);
    
    Class nilclass = [rootclass superclass];
    Class superrootmeta = [rootmeta superclass];
    
    NSLog(@"s address:%p", s);
    NSLog(@"cls address:%p", cls);
    NSLog(@"meta address:%p", meta);
    NSLog(@"superclass address:%p", superclass);
    NSLog(@"supermeta address:%p", supermeta);
    NSLog(@"supermeta2 address:%p", supermeta2);
    NSLog(@"rootclass address:%p", rootclass);
    NSLog(@"rootmeta address:%p", rootmeta);
    NSLog(@"rootmeta2 address:%p", rootmeta2);
    NSLog(@"nilclass address:%p", nilclass);
    NSLog(@"superrootmeta address:%p", superrootmeta);

打印結(jié)果

2017-04-26 12:32:10.412 runtimeDemo[1194:22584480] s address:0x608000015700
2017-04-26 12:32:10.412 runtimeDemo[1194:22584480] cls address:0x10540f060
2017-04-26 12:32:10.412 runtimeDemo[1194:22584480] meta address:0x10540f038
2017-04-26 12:32:10.412 runtimeDemo[1194:22584480] superclass address:0x10540f0b0
2017-04-26 12:32:10.413 runtimeDemo[1194:22584480] supermeta address:0x10540f088
2017-04-26 12:32:10.413 runtimeDemo[1194:22584480] supermeta2 address:0x10540f088
2017-04-26 12:32:10.413 runtimeDemo[1194:22584480] rootclass address:0x105da8e88
2017-04-26 12:32:10.413 runtimeDemo[1194:22584480] rootmeta address:0x105da8e38
2017-04-26 12:32:10.413 runtimeDemo[1194:22584480] rootmeta2 address:0x105da8e38
2017-04-26 12:32:10.413 runtimeDemo[1194:22584480] nilclass address:0x0
2017-04-26 12:32:10.413 runtimeDemo[1194:22584480] superrootmeta address:0x105da8e88

通過結(jié)果可以看出,結(jié)果與圖示相符嫡秕。

FAQ:
1.class方法和object_getClass有區(qū)別么渴语?
細(xì)心的朋友可能發(fā)現(xiàn)了,上面有的時(shí)候用class方法淘菩,有的時(shí)候用object_getClass方法遵班。讓我們看一下源碼

+ (Class)class {
    return self;
}
- (Class)class {
    return object_getClass(self);
}
  • 類方法class屠升,返回的是self潮改,所以當(dāng)查找meta class時(shí),需要對類對象調(diào)用object_getClass方法
  • 實(shí)例方法class腹暖,內(nèi)部實(shí)現(xiàn)就是調(diào)用的object_getClass方法汇在,
    即實(shí)例對象調(diào)用class,或?qū)?shí)例對象使用object_getClass()時(shí)脏答,返回的確實(shí)是實(shí)例對象的cls糕殉,但實(shí)例對象內(nèi)部的cls保存的是類對象,而不是meta class

ps: 附上一些有關(guān)meta class的文章
http://www.reibang.com/p/45fe90253519
http://blog.csdn.net/beclosedtomyheart/article/details/50164353
http://blog.csdn.net/windyitian/article/details/19810875

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末殖告,一起剝皮案震驚了整個(gè)濱河市阿蝶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌黄绩,老刑警劉巖羡洁,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異爽丹,居然都是意外死亡筑煮,警方通過查閱死者的電腦和手機(jī)辛蚊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來真仲,“玉大人袋马,你說我怎么就攤上這事〗沼Γ” “怎么了虑凛?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長灸眼。 經(jīng)常有香客問我卧檐,道長,這世上最難降的妖魔是什么焰宣? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任霉囚,我火速辦了婚禮,結(jié)果婚禮上匕积,老公的妹妹穿的比我還像新娘盈罐。我一直安慰自己,他們只是感情好闪唆,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布盅粪。 她就那樣靜靜地躺著,像睡著了一般悄蕾。 火紅的嫁衣襯著肌膚如雪票顾。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天帆调,我揣著相機(jī)與錄音奠骄,去河邊找鬼。 笑死番刊,一個(gè)胖子當(dāng)著我的面吹牛含鳞,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播芹务,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蝉绷,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了枣抱?” 一聲冷哼從身側(cè)響起熔吗,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎佳晶,沒想到半個(gè)月后桅狠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年垂攘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了维雇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,090評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡晒他,死狀恐怖吱型,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情陨仅,我是刑警寧澤津滞,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站灼伤,受9級特大地震影響触徐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜狐赡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一撞鹉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧颖侄,春花似錦鸟雏、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至展蒂,卻和暖如春又活,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背锰悼。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工柳骄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人松捉。 一個(gè)月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓夹界,卻偏偏與公主長得像馆里,于是被迫代替她去往敵國和親隘世。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評論 2 355

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