本文參考地址:https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtHowMessagingWorks.htmlhtml
本文主要分析了與Objective-C Runtime密切相關的幾個數據類型/概念:Class , Method,,SEL , IMP ,他們都在objc/objc.h中定義。先來看看他們的定義。緩存
typedef struct objc_class *Class; typedef struct objc_object { Class isa; } *id;//能夠看到,iOS中很重要的id實際上就是objc_object的指針.而NSObject的第一個對象就是Class類型的isa。所以id能夠標示全部基於NSObject的對象。 typedef struct objc_selector *SEL; #if !OBJC_OLD_DISPATCH_PROTOTYPES typedef void (*IMP)(void /* id, SEL, ... */ ); #else typedef id (*IMP)(id, SEL, ...); #endif
一,Classapp
Class 被定義爲一個指向objc_class的結構體指針,表示一個類的類結構。objc_class在objc/objc_class.h中定義以下:ide
struct objc_class { Class isa; #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;
可見,Class是指向類結構體的指針,該類結構體含有一個指向其父類類結構的指針,該類方法的鏈表,該類方法的緩存以及其餘信息。函數
NSObject 的class方法就返回這樣一個指向其類結構的指針。每個基於NSObject的類實例對象都有一個指向該對象的類結構的指針,叫作isa。經過該指針,對象能夠訪問它對應的類以及相應的父類。ui
二,Methodurl
Method是Runtime內部定義的方法,Class中定義有一個objc_method_list,鏈表都是objc_method類型的,定義以下:spa
typedef struct objc_method *Method; struct objc_method { SEL method_name OBJC2_UNAVAILABLE;/*標示方法名稱*/ char *method_types OBJC2_UNAVAILABLE;/*方法的參數類型*/ IMP method_imp OBJC2_UNAVAILABLE;/*指向該方法的具體實現的函數指針*/ } struct objc_method_list { struct objc_method_list *obsolete OBJC2_UNAVAILABLE; int method_count OBJC2_UNAVAILABLE; #ifdef __LP64__ int space OBJC2_UNAVAILABLE; #endif /* variable length structure */ struct objc_method method_list[1] OBJC2_UNAVAILABLE; }
三,SEL.net
定義以下:設計
typedef struct objc_selector *SEL;
標示該方法的名字/簽名
示例:
-(void)helloTekuba:(NSString *)url port:(int)port
{
NSLog(@"%@,%d",url,port);
}
NSLog(@"SEL = %s",@selector(helloTekuba:port:));
打印結果:
SEL = helloTekuba:port:
不一樣的類能夠擁有相同的selector,不一樣類的實例對象performSelector相同的selector時,會在各自的方法鏈表中根據 selector 去查找具體的方法實現IMP, 而後用這個方法實現去執行具體的實現代碼。這是一個動態綁定的過程,在編譯的時候,咱們不知道最終會執行哪一些代碼,只有在執行的時候,經過selector去查詢,咱們才能肯定具體的執行代碼。
四,IMP
typedef id (*IMP)(id, SEL, ...);
咱們知道 id是一個指向 objc_object 結構體的指針(請看本文前面objc_object的定義),該結構體只有一個成員isa,因此任何繼承自 NSObject 的類對象均可以用id 來指代,由於 NSObject 的第一個成員實例就是isa。
IMP 是一個函數指針,這個被指向的函數包含一個接收消息的對象id, 調用方法的選標 SEL,以及不定個數的方法參數,並返回一個id。也就是說IMP是消息最終調用的執行代碼,是方法真正的實現代碼 。咱們能夠像在C語言裏面同樣使用這個函數指針。
NSObject 類中的methodForSelector:方法就是這樣一個獲取指向方法實現IMP 的指針,methodForSelector:返回的指針和賦值的變量類型必須徹底一致,包括方法參數類型和返回值類型。
五,其餘
Ivar
Runtime中用來表示instance variable,實例變量,跟某個對象關聯,不能被靜態方法使用,與之想對應的是class variable,其聲明以下:
typedef struct objc_ivar *Ivar;
Category
Runtime中用來表示Category,其聲明爲:
typedef struct objc_category *Category;
Catagory能夠動態地爲已經存在的類添加新的行爲。這樣能夠保證類的原始設計規模較小,功能增長時再逐步擴展。使用Category對類進行擴展時,不須要訪問其源代碼,也不須要建立子類。關於更多Catagory的知識能夠參考:http://www.tekuba.net/program/312/