標籤: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)