刨根问底Objective-C Runtime(2)- Object Class Meta Class
Chun Tips
專注iOS開發刨根問底Objective-C Runtime(2)- Object & Class & Meta Class
上一篇筆記講述了objc runtime中Self 和 Super的細節,本篇筆記主要是講述objc runtime中關于Object & Class & Meta Class的細節。
習題內容
下面代碼的運行結果是?
@interface Sark : NSObject @end@implementation Sark @endint main(int argc, const char * argv[]) {@autoreleasepool {BOOL res1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];BOOL res2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];BOOL res3 = [(id)[Sark class] isKindOfClass:[Sark class]];BOOL res4 = [(id)[Sark class] isMemberOfClass:[Sark class]];NSLog(@"%d %d %d %d", res1, res2, res3, res4);}return 0; }運行結果為:
2014-11-05 14:45:08.474 Test[9412:721945] 1 0 0 0這里先看幾個概念
什么是 id
id?在 objc.h 中定義如下:
/// A pointer to an instance of a class. typedef struct objc_object *id;就像注釋中所說的這樣 id 是指向一個?objc_object?結構體的指針。
id 這個struct的定義本身就帶了一個 *, 所以我們在使用其他NSObject類型的實例時需要在前面加上 *, 而使用 id 時卻不用。
那么objc_object又是什么呢
objc_object?在 objc.h 中定義如下:
/// Represents an instance of a class. struct objc_object {Class isa; };這個時候我們知道Objective-C中的object在最后會被轉換成C的結構體,而在這個struct中有一個?isa?指針,指向它的類別 Class。
那么什么是Class呢
在 objc.h 中定義如下:
/// An opaque type that represents an Objective-C class. typedef struct objc_class *Class;我們可以看到 Class本身指向的也是一個C的struct?objc_class。
繼續看在runtime.h中objc_class定義如下:
struct objc_class {Class isa OBJC_ISA_AVAILABILITY;#if !__OBJC2__Class super_class OBJC2_UNAVAILABLE;const char *name OBJC2_UNAVAILABLE;long version OBJC2_UNAVAILABLE;long info OBJC2_UNAVAILABLE;long instance_size OBJC2_UNAVAILABLE;struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;struct objc_method_list **methodLists OBJC2_UNAVAILABLE;struct objc_cache *cache OBJC2_UNAVAILABLE;struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;#endif } OBJC2_UNAVAILABLE;該結構體中,isa?指向所屬Class,?super_class指向父類別。
繼續看
下載objc源代碼,在?objc-runtime-new.h?中,我們發現?objc_class有如下定義:
struct objc_class : objc_object {// Class ISA;Class superclass; ...... }豁然開朗,我們看到在Objective-C的設計哲學中,一切都是對象。Class在設計中本身也是一個對象。而這個Class對象的對應的類,我們叫它?Meta Class。即Class結構體中的?isa?指向的就是它的?Meta Class。
Meta Class
根據上面的描述,我們可以把Meta Class理解為?一個Class對象的Class。簡單的說:
- 當我們發送一個消息給一個NSObject對象時,這條消息會在對象的類的方法列表里查找
- 當我們發送一個消息給一個類時,這條消息會在類的Meta Class的方法列表里查找
而 Meta Class本身也是一個Class,它跟其他Class一樣也有自己的?isa?和?super_class?指針。看下圖:
- 每個Class都有一個isa指針指向一個唯一的Meta Class
- 每一個Meta Class的isa指針都指向最上層的Meta Class(圖中的NSObject的Meta Class)
- 最上層的Meta Class的isa指針指向自己,形成一個回路
- 每一個Meta Class的super class指針指向它原本Class的 Super Class的Meta Class。但是最上層的Meta Class的 Super Class指向NSObject Class本身
- 最上層的NSObject Class的super class指向 nil
解惑
為了更加清楚的知道整個函數調用過程,我們使用clang -rewrite-objc main.m重寫,可獲得如下代碼:
BOOL res1 = ((BOOL (*)(id, SEL, Class))(void *)objc_msgSend)((id)((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("class")), sel_registerName("isKindOfClass:"), ((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("class")));BOOL res2 = ((BOOL (*)(id, SEL, Class))(void *)objc_msgSend)((id)((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("class")), sel_registerName("isMemberOfClass:"), ((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("class")));BOOL res3 = ((BOOL (*)(id, SEL, Class))(void *)objc_msgSend)((id)((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Sark"), sel_registerName("class")), sel_registerName("isMemberOfClass:"), ((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("class")));BOOL res4 = ((BOOL (*)(id, SEL, Class))(void *)objc_msgSend)((id)((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Sark"), sel_registerName("class")), sel_registerName("isMemberOfClass:"), ((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("class")));先看前兩個調用:
- 最外層是?objc_msgSend函數,轉發消息。
- 函數第一個參數是?(id)((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("class"))
- 函數第二個參數是轉發的selector
- 函數第三個參數是?((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("class"))
我們注意到第一個參數和第三個參數對應重寫的是[NSObject class],即使用objc_msgSend向 NSObject Class 發送 @selector(class) 這個消息
打開objc源代碼,在?Object.mm?中發現+ (Class)class實現如下:
+ (Class)class {return self; }所以即返回Class類的對象本身。看如下輸出:
NSLog(@"%p", [NSObject class]); NSLog(@"%p", [NSObject class]);2014-11-05 18:48:30.939 Test[11682:865988] 0x7fff768d40f0 2014-11-05 18:48:30.940 Test[11682:865988] 0x7fff768d40f0繼續打開objc源代碼,在?Object.mm?中,我們發現?isKindOfClass的實現如下:
- (BOOL)isKindOf:aClass {Class cls;for (cls = isa; cls; cls = cls->superclass) if (cls == (Class)aClass)return YES;return NO; }對著上面Meta Class的圖和實現,我們可以看出
- 當 NSObject Class對象第一次進行比較時,得到它的isa為 NSObject的Meta Class, 這個時候 NSObject Meta Class 和 NSObject Class不相等。
(這里應為是類函數的調用所以isa是元類, 如果是實例對象isa就不是元類而是類對象)
- 然后取NSObject 的Meta Class 的Super class,這個時候又變成了 NSObject Class, 所以返回相等
所以上述第一個輸出結果是?YES?。
我們在看下 ‘isMemberOfClass’的實現:
- (BOOL)isMemberOf:aClass {return isa == (Class)aClass; }綜上所述,當前的 isa 指向 NSObject 的 Meta Class, 所以和 NSObject Class不相等。
所以上述第二個輸出結果為?NO?。
繼續看后面兩個調用:
- Sark Class 的isa指向的是 Sark的Meta Class,和Sark Class不相等
- Sark Meta Class的super class 指向的是 NSObject Meta Class, 和 Sark Class不相等
- NSObject Meta Class的 super class 指向 NSObject Class,和 Sark Class 不相等
- NSObject Class 的super class 指向 nil, 和 Sark Class不相等
所以后面兩個調用的結果都輸出為?NO?。
下一篇博客的主要分享的內容是關于 Objective C Runtime中 消息和Category 的學習筆記。
- 本文是關于Objective C Runtime的學習筆記。有不對的地方,歡迎大家指正。
- 感謝@唐巧_boy和@sunnyxx分享題目。
- 本文由@Chun發表于Chun Tips?.
- 版權聲明:自由轉載-非商用-非衍生-保持署名 |?Creative Commons BY-NC-ND 3.0
Chun Tips正在使用多說
Copyright ? 2015 - Chun Ye -?Powered by?Octopress
posted on 2015-06-26 16:29 城之內 閱讀(...) 評論(...) 編輯 收藏轉載于:https://www.cnblogs.com/HypeCheng/p/4602603.html
總結
以上是生活随笔為你收集整理的刨根问底Objective-C Runtime(2)- Object Class Meta Class的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linq to sql简单使用
- 下一篇: 关于bin和obj文件夹。debug 和