上一節Objective-C的對象——實例對象、類對象、元類對象我們總結出:
OC中的對象分成三類,分別包括: instance(實例對象)、class(類對象)、meta-class(元類對象)。如下圖,并且我們發現①實例對象都會存儲類的成員變量,其中有一個特殊的成員變量就是isa。②類對象存儲 isa、superclass、成員變量相關的信息、協議信息、屬性、對象方法等信息。③元類對象存儲isa、superclass、類方法。通過上面對比三種OC對象,我們可以發現有兩個很的特殊的指針:isa指針和superclass指針。其中instance、class、meta-class三種對象都有isa指針,而class、meta-class兩種對象都有superclass指針。那今天我們就聊一下isa指針和superclass指針。
三種OC對象是如何聯系的?
在聊isa和superclass之前,我們先討論一個問題:一個自定義Person類的實例對象p,要想調用對象方法(- personInstanceMethod)和類方法(+ personClassMethod),它的底層是如何實現的?
@interface Person : NSObject
- (void)personInstanceMethod;
+ (void)personClassMethod;
@end
@implementation Person
- (void)personInstanceMethod {
}
+ (void)personClassMethod {
}
@end
// mian方法中
Person *p = [[Person alloc] init];
[p personInstanceMethod];
[Person personClassMethod];;
上面的代碼我們聲明了一個Person類,并且有一個對象方法和一個類方法,在程序的main方法中alloc、init了一個指針名為p
的實例對象,分別用p
調用對象方法personInstanceMethod
,用Person
調用類方法personClassMethod
。我們知道OC中是通過消息發送機制來調用方法的,我們可以把[p personInstanceMethod]
這句代碼翻譯成底層調用代碼為objc_msgSend(p, @selector(personInstanceMethod));
,我們發現,OC底層的代碼是向p
這個實例對象發送消息的,但是我們知道:對象方法的信息其實是在Person
類對象里面存儲的,因此我們可以猜想實例對象
和類對象
擁有某種聯系。同理我們使用Person類對象
調用類方法personClassMethod
,objc_msgSend方法是向類對象Person發送消息的,但我們知道類對象并沒有存儲類方法,而元類對象有存儲類方法,因此類對象和元類對象也是有一定的聯系。
我們也可以通過xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp 命令讓其轉化成C、C++代碼觀察
OC對象的isa指向哪里?
通過對上面問題的討論,我們可以猜想instance、class、meta-class三種對象是有一定聯系的。其實他們是通過isa指針去聯系起來的。
實例對象的isa指向類對象,類對象的isa指向元類對象。
①實例對象的isa指向類對象,當調用對象方法時,通過instance的isa找到class,最后找到對象方法的實現進行調用。
(例如:上面的例子,實例對象p
調用personInstanceMethod
對象方法,其實是通過實例對象的isa指針先找到類對象Person
,再從類對象的內從中找到personInstanceMethod
的方法實現進行調用)
②類對象的isa指向元類對象,當調用類對象方法時,通過類對象的isa找到元類對象,最后找到類方法的實現進行調用。
(例如:上面的例子,類對象Person
調用personClassMethod
類方法,其實是通過類對象的isa指針先找到元類對象meta-person
,再從元類對象的內從中找到personInstanceMethod
的方法實現進行調用)
擁有繼承關系的對象是如何聯系的?
isa
指針只是解決了一個類中的聯系,但是如果擁有繼承關系的類之間又是通過什么聯系的呢?在討論這個問題之前我們再來做一個場景:
在(三種OC對象是如何聯系的?)的代碼的基礎上我們再添加一個繼承于Person
這個類的Student
類,并聲明和實現了類方法 studentClassMethod
和 對象方法 studentInstanceMethod
。
@interface Person : NSObject
- (void)personInstanceMethod;
+ (void)personClassMethod;
@end
@implementation Person
- (void)personInstanceMethod {
}
+ (void)personClassMethod {
}
@end
@interface Student : Person
- (void)studentInstanceMethod;
+ (void)studentClassMethod;
@end
@implementation Student
- (void)studentInstanceMethod {
}
+ (void)studentClassMethod {
}
@end
//main 方法中
Student *stu = [[Student alloc] init];
[stu studentInstanceMethod]; //①
[stu personInstanceMethod]; //②
[Student studentClassMethod]; //③
[Student personClassMethod]; //④
我們先看①:stu
實例對象調用實例方法studentInstanceMethod
,通過我們剛才的討論,stu
實例對象先通過它自己的isa指針找到Student
類對象,再找到實例方法的實現從而進行調用。
接著我們再看③:Student
類對象調用類方法studentClassMethod
,也是通過我們剛才的討論,Student
類對象先通過它自己的isa指針找到meta-class
元類對象,再找到類方法的實現從而進行調用。
但是我們再看看②和④就會發現,Student
類對象和元類對象都沒有personInstanceMethod
和personClassMethod
的方法,那么又是怎么去實現的呢?
superclass指針指向哪里?
在上面的(擁有繼承關系的對象是如何聯系的?),我們發現子類和父類之間需要有一定的聯系,才能讓子類去調用父類聲明的方法還有使用父類的成員屬性等。那又是通過什么去聯系的呢?其實它們之間就是通過superclass指針去聯系的。不過類對象的
superclass
指針和元類對象的superclass
稍微有一些不同,我們先說一下類對象的superclass
指針。
現在各個類的繼承關系如下: @interface Student : Person
,@interface Person : NSObject
, Student 類對象、 Person 類對象、NSObject 類對象 它們都各自存放著各自的 isa、superclass、成員變量相關的信息、協議信息、屬性、對象方法,這三個類對象的聯系其實很簡單,他們就是通過superclass指針聯系起來的。
Student類對象的superclass指針指向Person類對象,Person類對象的superclass指針指向NSObject類對象。
因此我們可以解答剛才的問題,stu
實例對象是如何調用父類的實例方法:personInstanceMethod?
Student *stu = [[Student alloc] init];
[stu personInstanceMethod];
由于Student類繼承于Person類,上面的方法調用通過轉換成C、C++語言其實就是:objc_msgSend(stu, @selector(personInstanceMethod));
,stu實例對象是不存儲方法信息的,因此通過isa指針先找到它的類對象Student,但Student類對象并沒有該方法,所以可以通過Student類對象的superclass指針找到Person類對象,從而找到personInstanceMethod的方法實現并調用。
我們說完類對象
的superclass
指針,再說以元類對象
的superclass
指針。我們還是使用上面的繼承關系:@interface Student : Person
,@interface Person : NSObject
。
Student元類對象的superclass指針指向Person元類對象,Person元類對象的superclass指針指向NSObject元類對象。
[Student personClassMethod];
上面的方法調用通過轉換成C、C++語言其實就是:objc_msgSend(Student, @selector(personClassMethod));
,Student類對象的isa找到Student的元類對象,但Student元類對象的類方法列表并沒有personClassMethod,因此通過Student元類對象的superclass指針找到Person元類對象,從而找到哦personClassMethod的方法實現并進行調用。
通過上面討論類對象的superclass指針和元類對象的superclass指針我們可以得到的信息就是:
類對象的superclass指針指向它父類的類對象。
元類對象的superclass指針指向它父類的元類對象。
isa、superclass總結
instance的isa指向class
class的isa指向meta-class
meta-class的isa指向基類的meta-class
class的superclass指向父類的class,如果沒有父類,superclass指針為nil
meta-class的superclass指向父類的meta-class;基類的meta-class的superclass指向基類的class
instance調用對象方法的軌跡;isa找到class,方法不存在,就通過superclass找父類
class調用類方法的軌跡;isa找meta-class,方法不存在,就通過superclass找父類