原文鏈接:關(guān)于CLASS
cocoa當(dāng)中的函數(shù)調(diào)用,是一種以消息的方式進(jìn)行的函數(shù)調(diào)用纲辽,這一點(diǎn)與C++啦吧,java是有很大差別的您觉。因此該類型的理解,會(huì)涉及到三個(gè)重要的概念授滓,class琳水,sel,IMP般堆。
class
每個(gè)NSObject的第一個(gè)成員變量都是class類型的成員在孝,isa,這個(gè)isa的對(duì)象可以訪問到本類的父類淮摔,也可以訪問到本類的所有方法的列表私沮。
含義
Class 被定義為一個(gè)指向 objc_class的結(jié)構(gòu)體指針,這個(gè)結(jié)構(gòu)體表示每一個(gè)類的類結(jié)構(gòu)和橙。而 objc_class 在objc/objc_class.h中定義如下:
struct objc_class {
struct objc_class super_class;? /*父類*/
const char *name;? ? ? ? ? ? ? ? /*類名字*/
long version;? ? ? ? ? ? ? ? ? /*版本信息*/
long info;? ? ? ? ? ? ? ? ? ? ? ? /*類信息*/
long instance_size;? ? ? ? ? ? ? /*實(shí)例大小*/
struct objc_ivar_list *ivars;? ? /*實(shí)例參數(shù)鏈表*/
struct objc_method_list **methodLists;? /*方法鏈表*/
struct objc_cache *cache;? ? ? ? ? ? ? /*方法緩存*/
struct objc_protocol_list *protocols;? /*協(xié)議鏈表*/
};
由此可見仔燕,Class 是指向類結(jié)構(gòu)體的指針,該類結(jié)構(gòu)體含有一個(gè)指向其父類類結(jié)構(gòu)的指針魔招,該類方法的鏈表晰搀,該類方法的緩存以及其他必要信息。
NSObject 的class 方法就返回這樣一個(gè)指向其類結(jié)構(gòu)的指針办斑。每一個(gè)類實(shí)例對(duì)象的第一個(gè)實(shí)例變量是一個(gè)指向該對(duì)象的類結(jié)構(gòu)的指針外恕,叫做isa。通過該指針乡翅,對(duì)象可以訪問它對(duì)應(yīng)的類以及相應(yīng)的父類鳞疲。如圖一所示:
如圖一所示,圓形所代表的實(shí)例對(duì)象的第一個(gè)實(shí)例變量為 isa蠕蚜,它指向該類的類結(jié)構(gòu) The object’s class尚洽。而該類結(jié)構(gòu)有一個(gè)指向其父類類結(jié)構(gòu)的指針superclass, 以及自身消息名稱(selector)/實(shí)現(xiàn)地址(address)的方法鏈表波势。
方法的含義:
注意這里所說的方法鏈表里面存儲(chǔ)的是Method 類型的翎朱。圖一中selector 就是指 Method的 SEL,? address就是指Method的 IMP。 Method 在頭文件 objc_class.h中定義如下:
typedef struct objc_method *Method;
typedef struct objc_ method {
SEL method_name;
char *method_types;
IMP method_imp;
};
一個(gè)方法 Method尺铣,其包含一個(gè)方法選標(biāo) SEL – 表示該方法的名稱拴曲,一個(gè)types – 表示該方法參數(shù)的類型,一個(gè) IMP? - 指向該方法的具體實(shí)現(xiàn)的函數(shù)指針凛忿。
SEL
這個(gè)是方法名稱的描述澈灼。
在前面我們看到方法選標(biāo) SEL 的定義為:
typedef struct objc_selector? *SEL;
它是一個(gè)指向 objc_selector 指針,表示方法的名字/簽名。如下所示叁熔,打印出 selector委乌。
-(NSInteger)maxIn:(NSInteger)a theOther:(NSInteger)b
{
return (a > b) ? a : b;
}
NSLog(@"SEL=%s", @selector(maxIn:theOther:));
輸出:SEL=maxIn:theOther:
不同的類可以擁有相同的 selector,這個(gè)沒有問題荣回,因?yàn)椴煌惖膶?shí)例對(duì)象performSelector相同的 selector 時(shí)遭贸,會(huì)在各自的消息選標(biāo)(selector)/實(shí)現(xiàn)地址(address) 方法鏈表中根據(jù) selector 去查找具體的方法實(shí)現(xiàn)IMP, 然后用這個(gè)方法實(shí)現(xiàn)去執(zhí)行具體的實(shí)現(xiàn)代碼。這是一個(gè)動(dòng)態(tài)綁定的過程心软,在編譯的時(shí)候壕吹,我們不知道最終會(huì)執(zhí)行哪一些代碼,只有在執(zhí)行的時(shí)候删铃,通過selector去查詢耳贬,我們才能確定具體的執(zhí)行代碼。
IMP
這個(gè)是具體的方法的地址猎唁。
在前面我們也看到 IMP 的定義為:
typedef id (*IMP)(id, SEL, ...);
根據(jù)前面id 的定義咒劲,我們知道 id是一個(gè)指向 objc_object 結(jié)構(gòu)體的指針,該結(jié)構(gòu)體只有一個(gè)成員isa诫隅,所以任何繼承自 NSObject 的類對(duì)象都可以用id 來指代腐魂,因?yàn)?NSObject 的第一個(gè)成員實(shí)例就是isa。
至此阎肝,我們就很清楚地知道 IMP? 的含義:IMP 是一個(gè)函數(shù)指針挤渔,這個(gè)被指向的函數(shù)包含一個(gè)接收消息的對(duì)象id(self? 指針), 調(diào)用方法的選標(biāo) SEL (方法名),以及不定個(gè)數(shù)的方法參數(shù)风题,并返回一個(gè)id。也就是說 IMP 是消息最終調(diào)用的執(zhí)行代碼嫉父,是方法真正的實(shí)現(xiàn)代碼 沛硅。我們可以像在C語言里面一樣使用這個(gè)函數(shù)指針。
NSObject 類中的methodForSelector:方法就是這樣一個(gè)獲取指向方法實(shí)現(xiàn)IMP 的指針绕辖,methodForSelector:返回的指針和賦值的變量類型必須完全一致摇肌,包括方法的參數(shù)類型和返回值類型。
下面的例子展示了怎么使用指針來調(diào)用setFilled:的方法實(shí)現(xiàn):
void (*setter)(id, SEL, BOOL);
int i;
setter = (void(*)(id, SEL, BOOL))[target methodForSelector:@selector(setFilled:)];
for (i = 0; i < 1000; i++)
setter(targetList[i], @selector(setFilled:), YES);
使用methodForSelector:來避免動(dòng)態(tài)綁定將減少大部分消息的開銷仪际,但是這只有在指定的消息被重復(fù)發(fā)送很多次時(shí)才有意義围小,例如上面的for循環(huán)。
注意树碱,methodForSelector:是Cocoa運(yùn)行時(shí)系統(tǒng)的提供的功能肯适,而不是Objective-C語言本身的功能。
幾個(gè)重要的輔助函數(shù)成榜,可以在使用過程中起到很好的輔助作用框舔,尤其是在動(dòng)態(tài)編譯等起到了比較大的作用。
我們可以通過NSObject的一些方法獲取運(yùn)行時(shí)信息或動(dòng)態(tài)執(zhí)行一些消息:
class? 返回對(duì)象的類;
isKindOfClass 和 isMemberOfClass檢查對(duì)象是否在指定的類繼承體系中刘绣;
respondsToSelector 檢查對(duì)象能否相應(yīng)指定的消息樱溉;
conformsToProtocol 檢查對(duì)象是否實(shí)現(xiàn)了指定協(xié)議類的方法;
methodForSelector? 返回指定方法實(shí)現(xiàn)的地址纬凤。
performSelector:withObject 執(zhí)行SEL 所指代的方法福贞。