《轉》Objective-C Runtime(2)- Object & Class & Meta Class

習題內容

下面代碼的運行結果是?函數

@interface Sark : NSObject
@end

@implementation Sark
@end

int 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 結構體的指針。code

id 這個struct的定義自己就帶了一個 *, 因此咱們在使用其餘NSObject類型的實例時須要在前面加上 *, 而使用 id 時卻不用。對象

那麼objc_object又是什麼呢

objc_object 在 objc.h 中定義以下:get

/// Represents an instance of a class.
struct objc_object {
    Class isa;
};

這個時候咱們知道Objective-C中的object在最後會被轉換成C的結構體,而在這個struct中有一個 isa 指針,指向它的類別 Class。it

那麼什麼是Class呢

在 objc.h 中定義以下:io

/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;

咱們能夠看到 Class自己指向的也是一個C的struct objc_classclass

繼續看在runtime.h中objc_class定義以下:object

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不相等。
  • 而後取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 。

相關文章
相關標籤/搜索