iOS 類和元類的關係

事情的始末是這樣的,同學想驗證一下resolveClassMethod是否執行(resolveClassMethod是一個對象調用一個不存在類方法時,會執行此方法,不懂的要惡補一下了,可以看我這篇文章:Objective-C消息轉發),然後發來瞭如下代碼:

[NSObject performSelector:@selector(hehe)];

當時看完之後產生了疑惑,performSelector是一個實例方法,NSObject是一個類,難道編譯不會報錯嗎?後來親測發現確實不會報錯。

然後開始了我們今天的故事:
我們都知道下面這樣寫一定會出錯

@interface TestObject : NSObject
@end
@implementation TestObject
- (void)method1{
       [TestObject method2];//這樣調用一定會編譯錯誤
}
- (void)method2{}

然而這樣寫卻不會報錯

@interface TestObject : NSObject
@end
@implementation TestObject
- (void)method{
   [NSObject performSelector:@selector(hehe)];
}

甚至於這樣寫也不會報錯
創建一個NSObject的類目

@interface NSObject (hehe)
+(void)run;
@end
@implementation NSObject (hehe)
-(void)run{
    NSLog(@"run.....");
}
@end

然後調用

[NSObject run];

這是爲什麼哪?

看一張關係圖

圖片.png

 

(此圖來源自網絡)
假設A類繼承自B類,B類繼承自NSObject
A便是途中的Subclass(class),B便是圖中的Superclass(class),NSObject便是Root class(class);
A *a = [A new];
其實A和a一樣,也是對象,A稱爲類對象,a稱爲實例對象
每一個類對象都有一個isa指針

 Class isa  OBJC_ISA_AVAILABILITY;

這個isa指針的指向就是該類對象的元類,每一個類都是它的元類的對象,元類是對類對象的描述,就像類是普通實例對象的描述一樣。

每一個類裏面聲明的類方法,其本質就是把該類方法放到元類的方法列表上面,所以類在調用類方法時,可以想象成是元類的對象在調用一個實例方法。

A的父類是B,A的元類的父類是B元類的父類,B的父類是NSObject,NSObject的父類是nil,B元類的父類是NSObject的元類;特別注意的一點,NSObject的元類的父類是NSObject,NSObject的isa指針又指向NSObject的元類,所以在NSObject裏面的所有方法,NSObject的元類也都擁有,1、所以用NSObject 調用任意NSObject裏面的實例方法都是可以成功的,2、這也就解釋了上面的聲明裏面是+(void)run;類方法,實現裏面是-(void)run{ NSLog(@"run.....");}實例方法,調用卻不會崩潰。

類和元類是一個閉環,實例指向類,類指向元類,元類指向跟元類,跟元類指向自身,根元類的父類是NSObject

元類是 Class 對象的類。每個類(Class)都有自己獨一無二的元類(每個類都有自己第一無二的方法列表)。這意味着所有的類對象都不同。

NSObject裏面的所有實力方法,任意類都可以通過類方法調用。

所有的meta-class使用基類的meta-class作爲自己的基類,對於頂層基類的meta-class也是一樣,只是它指向自己而已

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章