iOS RunTime 學習記錄1_類和物件
前言:我是參考 南峰子 的部落格加上自己理解寫的,原著專輯大家自己可看:http://southpeak.github.io/categories/objectivec/
iOS中的類(Class)和物件(objc)都是在RunTime 中實現的,自己學習人家的部落格做點筆記,提醒一下自己:
類(Class)
為什麼RunTime和這些扯上關係了,好吧,看看人家的目錄結構你會發現在OC程式碼的執行都是離不開RunTime。而程式碼無非就是類與方法,所以執行時定義了類和方法,並控制他們的執行方式。目錄結構如下:
Objective-C 中的類使用的是objc_class 這個結構體表示,在目錄objc/runtime.h中檢視:
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結構本身也是一個物件,裡面的isa指標指向的就是這個物件對應的類,但是Class物件指向的這個類叫做元類metaClass(下面介紹),在這個類呼叫類方法就可以看出元類的作用了。
super_class
父類,如果該類已經是最頂層的根類(如NSObject或NSProxy),則super_class為NULL
name
類名
cache
struct objc_cache {
unsigned int mask /* total = mask + 1 */ OBJC2_UNAVAILABLE;
unsigned int occupied OBJC2_UNAVAILABLE;
Method buckets[1] OBJC2_UNAVAILABLE;
};
- mask
一個整數,指定分配的快取bucket的總數。在方法查詢過程中,Objective-C runtime使用這個欄位來確定開始線性查詢陣列的索引位置。指向方法selector的指標與該欄位做一個AND位操作(index = (mask & selector))。這可以作為一個簡單的hash雜湊演算法 - occupied
一個整數,指定實際佔用的快取bucket的總數 - buckets
指向Method資料結構指標的陣列。這個陣列可能包含不超過mask+1個元素。需要注意的是,指標可能是NULL,表示這個快取bucket沒有被佔用,另外被佔用的bucket可能是不連續的。這個陣列可能會隨著時間而增長
應這個訊息的物件。在實際使用中,這個物件只有一部分方法是常用的,很多方法其實很少用或者根本用不上。這種情況下,如果每次訊息來時,我們都是methodLists中遍歷一遍,效能勢必很差。這時,cache就派上用場了。在我們每次呼叫過一個方法後,這個方法就會被快取到cache列表中,下次呼叫的時候runtime就會優先去cache中查詢,如果cache沒有,才去methodLists中查詢方法。這樣,對於那些經常用到的方法的呼叫,但提高了呼叫的效率。比如:
NSArray *array = [[NSArray alloc] init];
方法執行流程
1.[NSArray alloc]先被執行。因為NSArray沒有+alloc方法,於是去父類NSObject去查詢。
2.檢測NSObject是否響應+alloc方法,發現響應,於是檢測NSArray類,並根據其所需的記憶體空間大小開始分配記憶體空間,然後把isa指標指向NSArray類。同時,+alloc也被加進cache列表裡面。
3.接著,執行-init方法,如果NSArray響應該方法,則直接將其加入cache;如果不響應,則去父類查詢。
4,在後期的操作中,如果再以[[NSArray alloc] init]這種方式來建立陣列,則會直接從cache中取出相應的方法,直接呼叫。
物件(objc)
在objc/objc.h 中我們看到如下定義
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
可以發現物件結構體就一個isa指標(剛才不是說Class也是元類(metaClass)的物件,所以Class 資料結構中也有一個isa指標)。它指向這個物件對應的類Class上。
NSObject類的alloc和allocWithZone:方法使用函式建立物件時,會呼叫class_createInstance來建立這個物件結構體objc_objc。
當我們這個呼叫這個物件的方法selector,RunTime 會通過isa指標找到這個物件對應的類,然後在這個類的方法列表(objc_method_list)中查詢這個方法selector,如果找不到就往這個類的父類上面找。找到後執行這個方法。
特殊的類--元類(Meta Class)
上面我們說了,Class本身也是各物件,它也有isa指標,那麼它的isa指向了什麼地方了?答案就是Meta Class。
meta-class是一個類物件的類。
當我們向一個物件傳送訊息時,runtime會在這個物件所屬的這個類的方法列表中查詢方法;而向一個類傳送訊息時,會在這個類的meta-class的方法列表中查詢。
比如下面我們初始化NSArray用類方法實現:
NSArray *array = [NSArray array];
這裡 +array 方法被NSArray呼叫,這裡NSArray是個類,也是個物件objc_object,這個物件不是
通過alloc或allocWithZone:方法建立的,所以沒用
通過NSArray 父類NSObject最後通過Class 的class_createInstance建立objc_object。它本身就是objc_object,也有isa指標,為了找到這個方法,這個指標指向那了,其實就是指向NSArray的元類。
meta-class之所以重要,是因為它儲存著一個類的所有類方法
。每個類都會有一個單獨的meta-class,因為每個類的類方法基本不可能完全相同。
再深入一下,meta-class也是一個類,也可以向它傳送一個訊息,那麼它的isa又是指向什麼呢?為了不讓這種結構無限延伸下去,Objective-C的設計者讓所有的meta-class的isa指向基類的meta-class,以此作為它們的所屬類。即,任何NSObject繼承體系下的meta-class都使用NSObject的meta-class作為自己的所屬類,而基類的meta-class的isa指標是指向它自己。這樣就形成了一個完美的閉環。
結構圖:
[圖片上傳失敗...(image-70292-1513910965638)]
其中 Instance of SubClass是某個類的例項物件,它的isa 指標指向SubClass類,如果把Subclass類看成一個物件,那麼它的isa指向指向Subclass的元類(meta)。其中元類和元類之間繼承關係,不一定依賴於類於類之間繼承,但是最後指向了RootClass 根類和RootClass meta根類的元類。其中根類的元類(RootClass meta)又指向根類自己Root Class。
下面有個小例子,幫組自己理解一下
- (void)viewDidLoad {
[super viewDidLoad];
//例項方法-(Class)class,是獲取這個例項物件對應的類
//類方法+(Class)class 是獲取這個類(本身是個例項物件)對應的類
NSLog(@"這個類名是:%@ 父類名是:%@ 父父類名:%@ 父父父類:%@",[self class],[self superclass],[[self superclass] superclass],[[[self superclass] superclass] superclass]);
NSLog(@"NSObject這個類名:%@ 的地址:%p",[NSObject class],[NSObject class]);
NSLog(@"NSOject meta 地址:%p",objc_getClass((__bridge void *)[NSObject class]));
NSLog(@"這個類的地址:%p",[ViewController class]);
NSLog(@"這個物件地址:%p",self);
Class prClass = [self class];
/**
* for迴圈列印物件的isa地址
* 第一次列印的是這個物件對應的類(ViewController)的地址,也就是物件isa地址會發現其指向。
* 第二次列印的是ViewController看成物件後對應類的地址,也就是ViewController 的isa指向地址,也就是ViewController的元類。
* 第三次,第四次是元類的元類.....
*
*/
for (int i = 0; i< 5; i++) {
NSLog(@"迴圈第%i次列印物件isa地址:%p",i+1,prClass);
//objc_getClass得到一個類,根據類名(字串)得到。如果類再
prClass = objc_getClass((__bridge void *)prClass);
}
}
輸出結果:
**2016-07-27 11:45:40.088 RunTime_****類與物件****[73165:31955041] ****這個類名是:****ViewController ****父類名是:****UIViewController ****父父類名:****UIResponder ****父父父類****:NSObject**
**2016-07-27 11:45:40.088 RunTime_****類與物件****[73165:31955041] NSObject****這個類名:****NSObject ****的地址:****0x109145170**
**2016-07-27 11:45:40.089 RunTime_****類與物件****[73165:31955041] NSOject meta ****地址:****0x0**
**2016-07-27 11:45:40.089 RunTime_****類與物件****[73165:31955041] ****這個類的地址:****0x1088e7d58**
**2016-07-27 11:46:54.516 RunTime_****類與物件****[73165:31955041] ****這個物件地址:****0x7facd249fb40**
**2016-07-27 11:47:21.049 RunTime_****類與物件****[73165:31955041] ****迴圈第****1****次列印物件****isa****地址****:0x1088e7d58**
**2016-07-27 11:47:54.710 RunTime_****類與物件****[73165:31955041] ****迴圈第****2****次列印物件****isa****地址****:0x0**
**2016-07-27 11:47:54.711 RunTime_****類與物件****[73165:31955041] ****迴圈第****3****次列印物件****isa****地址****:0x0**
**2016-07-27 11:47:54.711 RunTime_****類與物件****[73165:31955041] ****迴圈第****4****次列印物件****isa****地址****:0x0**
**2016-07-27 11:47:54.711 RunTime_****類與物件****[73165:31955041] ****迴圈第****5****次列印物件****isa****地址****:0x0**
程式碼註釋中我說明了這種關係。我畫了一個簡易的圖如下:
好吧,第一課學習到這吧,我要改程式碼去了! 屌絲........
相關文章
- iOS runtime學習筆記iOS筆記
- Java學習筆記之類和物件Java筆記物件
- Scala 學習筆記(2)之類和物件筆記物件
- iOS KVC學習記錄iOS
- iOS KVO學習記錄iOS
- iOS GCD學習記錄iOSGC
- Java 學習:物件和類Java物件
- 1_文字記錄說明
- Java Math類方法學習記錄Java
- iOS學習筆記43 Swift(三)類iOS筆記Swift
- runtime(零) Objc 中類和物件的本質OBJ物件
- PHP 手冊 (類與物件) 學習筆記三:類常量PHP物件筆記
- PHP 手冊 (類與物件) 學習筆記十:抽象類PHP物件筆記抽象
- iOS @property及其關鍵字學習記錄iOS
- 【C++ Primer Plus】學習筆記--第10章 物件和類C++筆記物件
- C++ 一些學習筆記(十二)類和物件-多型C++筆記物件多型
- php使用佇列 SplQueue類學習記錄PHP佇列
- java學習中對類和物件的理解Java物件
- java基礎學習之一:物件和類Java物件
- PHP 手冊 (類與物件) 學習筆記七:物件繼承PHP物件筆記繼承
- MVVM的學習記錄和思考MVVM
- Python 學習筆記之類「物件導向,超類,抽象」Python筆記物件抽象
- 複習JAVA面相物件(類和物件)Java物件
- iOS類新增方法、屬性學習筆記iOS筆記
- C#學習筆記(一)--- 物件導向的思想和類的定義、物件的建立C#筆記物件
- 學習記錄
- Console物件的常用api學習記錄物件API
- 初識OC&iOS 類和物件iOS物件
- Kotlin學習筆記-類和介面Kotlin筆記
- Objective-C Runtime (一):類與物件Object物件
- 【每日學習記錄】使用錄影裝置記錄每天的學習
- JAVA程式設計學習記錄(API常用類(二))Java程式設計API
- PHP 手冊 (類與物件) 學習筆記二:屬性PHP物件筆記
- 記錄學習PromisePromise
- windbg學習記錄
- Eureka學習記錄
- Mybatis學習記錄MyBatis
- socket學習記錄