元類(meta class)

來源:互聯網
上載者:User

標籤:sas   開啟   ogr   簡化   類型   code   net   最新   9.png   

元類(meta class),這個名字想必很多人都聽過,網上也有很多關於元類的介紹,今天我就按照自己這兩天的理解來簡單探討一下這個玩意,有誤之處還望指出。

首先,下載objc源碼,源碼地址:https://opensource.apple.com/tarballs/objc4/
開啟連結後會發現有很多版本,我直接下載的最新版(709版本)

認識NSObject
1.開啟objc工程的NSObject.h,找到NSObject類的定義@interface NSObject <NSObject> {    Class isa  OBJC_ISA_AVAILABILITY;  //發現NSObject包含一個Class對象}2.繼續查看Class類型typedef struct objc_class *Class;3.繼續查看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;  //這個東西好像很牛逼,繼續看一下    ...}5.查看isa_t類型union isa_t {    isa_t() { }    isa_t(uintptr_t value) : bits(value) { }    Class cls;    //誒,這個東西又出現了    uintptr_t bits;}

簡單用圖片表示一下:


圖-1


那麼簡單總結一下就是,NSObject包含一個Class,Class中包含一個superclass和cls

meta class 擷取
1.開啟objc工程的runtime.h,找到meta class的擷取介面Class objc_getMetaClass(const char *name) {    //下面代碼進行了簡化    //1.通過類名找到類對象(注意不是類執行個體對象)    Class cls = objc_getClass (aClassName);    //2.返回上面圖-1中最裡面的cls    return cls->isa.cls;}2.meta class的擷取其實就是擷取類對象包含的cls,而我們在實際開發中是不能調用到cls的,這時,可以通過object_getClass來實現。查看object_getClass的實現Class object_getClass(id obj) {    //下面代碼經過簡化    return obj->isa.cls;  //也是返回cls}
通過測試代碼來分析源碼
//引入rumtime標頭檔#import <objc/objc-runtime.h>//定義一個簡單的類@interface Father : NSObject@property (nonatomic, strong) NSString *name;@end//各種執行個體列印    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]));

列印結果:

列印結果:2017-04-26 11:46:37.104 runtimeDemo[190:22480332] f address:0x600000011e702017-04-26 11:46:37.104 runtimeDemo[190:22480332] [f class] address:0x1063d5ff02017-04-26 11:46:37.105 runtimeDemo[190:22480332] [Father class] address:0x1063d5ff02017-04-26 11:46:37.105 runtimeDemo[190:22480332] objc_getMetaClass address:0x1063d5fc82017-04-26 11:46:37.105 runtimeDemo[190:22480332] objc_getClass address:0x1063d5fc8

通過結果進行分析:

  • 類執行個體對象本身不是元類
  • 類執行個體對象通過class方法擷取到的對象為類對象,[f class] == [Father class]
  • 通過類對象調用的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);

列印結果

2017-04-26 12:32:10.412 runtimeDemo[1194:22584480] s address:0x6080000157002017-04-26 12:32:10.412 runtimeDemo[1194:22584480] cls address:0x10540f0602017-04-26 12:32:10.412 runtimeDemo[1194:22584480] meta address:0x10540f0382017-04-26 12:32:10.412 runtimeDemo[1194:22584480] superclass address:0x10540f0b02017-04-26 12:32:10.413 runtimeDemo[1194:22584480] supermeta address:0x10540f0882017-04-26 12:32:10.413 runtimeDemo[1194:22584480] supermeta2 address:0x10540f0882017-04-26 12:32:10.413 runtimeDemo[1194:22584480] rootclass address:0x105da8e882017-04-26 12:32:10.413 runtimeDemo[1194:22584480] rootmeta address:0x105da8e382017-04-26 12:32:10.413 runtimeDemo[1194:22584480] rootmeta2 address:0x105da8e382017-04-26 12:32:10.413 runtimeDemo[1194:22584480] nilclass address:0x02017-04-26 12:32:10.413 runtimeDemo[1194:22584480] superrootmeta address:0x105da8e88

通過結果可以看出,結果與圖示相符。

FAQ:
1.class方法和object_getClass有區別嗎?
細心的朋友可能發現了,上面有的時候用class方法,有的時候用object_getClass方法。讓我們看一下源碼

+ (Class)class {    return self;}- (Class)class {    return object_getClass(self);}
  • 類方法class,返回的是self,所以當尋找meta class時,需要對類對象調用object_getClass方法
  • 執行個體方法class,內部實現就是調用的object_getClass方法,
    即執行個體對象調用class,或對執行個體對象使用object_getClass()時,返回的確實是執行個體對象的cls,但執行個體對象內部的cls儲存的是類對象,而不是meta class

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

元類(meta class)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.