事實上,在訊息傳遞的過程,當 someObject 這傢伙收到訊息之後,會順著這個物件的 isa 指針找到自己的類別,然後再依照收到的「訊息」去類別的 method list 找出對應的方法。如果在這個類別裡面找到了,就會直接執行它,如果找不到,會再往上一層父類別(super class)找。以上這個流程都是在程式執行過程中(Rumtime)才動態決定的,而不是在編譯(Compile)時期就決定好的。
// Animal Class
@interface Animal : NSObject
@end
@implementation Animal
@end
// Fox Class
@interface Fox : Animal
- (void) say;
@end
@implementation Fox
- (void) say
{
NSLog(@"What does the fox say!?");
}
@end
上面這段程式碼建立了兩個類別,分別是 Animal 及 Fox ,而且 Fox 繼承自 Animal,而 Animal 類別則是繼承自 NSObject 類別。
不管是「物件」或是「類別」,因為一樣都是物件,所以他們在收到訊息時的反應流程也是一樣的:
當對「物件」發送訊息的時候,它會順著這個物件的 isa 指針找到它的所屬類別,然後翻看看這個類別的 method list 有沒有符合的方法可以執行;
當對「類別」發送訊息的時候,它會順著這個類別的 isa 指針找到它的所屬類別(也就是我們待會要說明的 Meta Class),然後翻看看這個類別的 method list 有沒有符合的方法可以執行。
什麼是 Meta Class?
Meta 這個字我不太懂中文該怎麼翻譯比較好,有人翻譯成「元」,有人翻譯成「後設」,但我個人還是喜歡直接使用 Meta 這個詞就好。
剛剛在看類別的 objc_class 的定義的時候有提到類別的 Struct 裡也有一個 isa 指針,指向它所屬的類別,你可以想像成是它是「類別的類別」,也就是所謂的 Meta Class。
而 Meta Class 其實也是一種類別,所以也跟一般的類別一樣有 isa 跟 super_class 指針… 所以就可以把這整個的關係用一張圖表來解釋:
看圖說故事:
每個 Class (Fox, Animal, NSObject) 的 isa 指針都指向一個唯一的 Class,這個 Class 稱之為 Meta Class。
每個 Meta Class 的 isa 指針都是指向最上層的 Meta Class (在我們上面那段範例裡,就是 NSObject 的 Meta Class),而最上層的 Meta Class 的 isa 則是指向自己,形成一個迴路。
每個 Meta Class 的 super_class 指針都是指向它原本類別的 Super Class 的 Meta Class,但最上層的 Meta Class 的 super_class 則是指向 NSObject 類別本身。
Fox* lucky = [[Fox alloc] init];
[lucky say];
// about fox instance
NSLog(@"the class of lucky is %@, address = %p", [lucky class], [lucky class]);
// about Fox class
NSLog(@"Fox = %@, address = %p", [Fox class], [Fox class]);
NSLog(@"Fox's Super Class = %@, address = %p", [Fox superclass], [Fox superclass]);
Class metaClassOfFox = object_getClass([Fox class]);
NSLog(@"Fox's Meta Class = %p", metaClassOfFox);
NSLog(@"Fox's Meta Class's Super Class = %p", [metaClassOfFox superclass]);
Class metaMetaClassOfFox = object_getClass(metaClassOfFox);
NSLog(@"Fox's Meta Class's Meta Class = %p", metaMetaClassOfFox);
// about Animal class
NSLog(@"Animal = %@, address = %p", [Animal class], [Animal class]);
NSLog(@"Animal's Super Class = %@, address = %p", [Animal superclass], [Animal superclass]);
Class metaClassOfAnimal = object_getClass([Animal class]);
NSLog(@"Animal's Meta Class = %p", metaClassOfAnimal);
NSLog(@"Animal's Meta Class's Super Class = %p", [metaClassOfAnimal superclass]);
Class metaMetaClassOfAnimal = object_getClass(metaClassOfAnimal);
NSLog(@"Animal's Meta Class's Meta Class = %p", metaMetaClassOfAnimal);
// about NSObject class
NSLog(@"NSObject = %@, address = %p", [NSObject class], [NSObject class]);
NSLog(@"NSObject's Super Class = %@, address = %p", [NSObject superclass], [NSObject superclass]);
Class metaClassOfNSObject = object_getClass([NSObject class]);
NSLog(@"NSObject's Meta Class = %p", metaClassOfNSObject);
NSLog(@"NSObject's Meta Class's Super Class = %p", [metaClassOfNSObject superclass]);
Class metaMetaClassOfNSObject = object_getClass(metaClassOfNSObject);
NSLog(@"NSObject's Meta Class's Meta Class = %p", metaMetaClassOfNSObject);
輸出結果如下:
What does the fox say!?
the class of lucky is Fox, address = 0x100002260
Fox = Fox, address = 0x100002260
Fox's Super Class = Animal, address = 0x100002210
Fox's Meta Class = 0x100002238
Fox's Meta Class's Super Class = 0x1000021e8
Fox's Meta Class's Meta Class = 0x7fff77cce838
Animal = Animal, address = 0x100002210
Animal's Super Class = NSObject, address = 0x7fff77cce810
Animal's Meta Class = 0x1000021e8
Animal's Meta Class's Super Class = 0x7fff77cce838
Animal's Meta Class's Meta Class = 0x7fff77cce838
NSObject = NSObject, address = 0x7fff77cce810
NSObject's Super Class = (null), address = 0x0
NSObject's Meta Class = 0x7fff77cce838
NSObject's Meta Class's Super Class = 0x7fff77cce810
NSObject's Meta Class's Meta Class = 0x7fff77cce838
輸出結果可能在每個人的電腦上都不一樣,但從輸出的結果就能證明上面那張圖片的每個類別之間的關係。
要特別注意的是,你可能會覺得直接對類別發送 class 訊息就可以得到該類別的 Meta Class,事實上直接對類別發送 class 訊息只會得到該類別自己。要取得類別的 Meta Class,可以透過 object_getClass 來取得。