第十四條:理解“類對象”的用意
前面介紹了消息轉(zhuǎn)發(fā)的機制。然而,消息的接收者究竟是何物?
是對象自身嗎?
運行期系統(tǒng)如何知道某個對象的類型呢?
對象類型并非在編譯期就綁定好了,而是要在運行期查找。
而且還有個特殊的類型叫做id,它能指代任意的Objective-C對象類型。
一般情況下,應(yīng)該指明消息接收者的具體類型,這樣的話,如果向其發(fā)送了無法解讀的消息,那么編譯器就會產(chǎn)生警告信息。
而類型為id的對象則不然,編譯器假定它能響應(yīng)所有消息。
“在運行期檢查對象類型”這一操作也叫做“類型信息查詢”(introspection,“內(nèi)省”)。
這個強大而有用的特性內(nèi)置于Foundation框架的NSObject協(xié)議里,凡是由公共根類(即NSObject與NSProxy)繼承來的對象都要遵從此協(xié)議。
在程序中不要直接比較對象所屬的類,比較明智的做法是調(diào)用“類型信息查詢方法”。
每個Objective-C對象實例都是指向某塊內(nèi)存數(shù)據(jù)的指針。所以在聲明變量時,類型后面都要跟一個“ * ”
NSString *string = @“some string”;
對于通用的對象類型id,由于其本身已經(jīng)是指針了,所以我們可以這樣寫:
id string = @"some string”;
上面兩種定義方式語義相同。區(qū)別在于,如果聲明時指定了具體類型,那么在該類實例上調(diào)用其所沒有的方法時,編譯器會發(fā)出警告。
每個對象結(jié)構(gòu)體的首個成員是class類的變量。該變量定義了對象所屬的類,通常稱為“is a”指針。
typedef struct objc_class *Class;
struct objc_class {
Class isa;
Class super_class;
const char *name;
long version;
long info;
long instance_size;
struct objc_ivar_list *ivars;
struct objc_method_list **methodLists;
struct objc_cache *cache;
struct objc_protocol_list *protocols;
};
此結(jié)構(gòu)體存放類的“元數(shù)據(jù)”(metadata),例如類的實例實現(xiàn)了幾個方法,具備多少個實例變量等信息。
此結(jié)構(gòu)體的首個變量也是is a 指針,這說明Class本身也是Objective-C的對象。
結(jié)構(gòu)體里還有個變量叫做super_class,它定義了本類的超類。
類對象所屬的類型(也就是is a指針?biāo)赶虻念愋停┦橇硗庖粋€類,叫做“元類”(metaclass),用來表述類對象本身所具備的元數(shù)據(jù)。
“類方法”就定義在元類,因為這些方法可以理解成類對象的實例方法。
每個類僅有一個“類對象”,而每個“類對象”僅有一個與之相關(guān)的“元類”。
super_class指針確立了繼承關(guān)系
isa指針描述了實例所屬的類
在類繼承體系中查詢類型的信息
isMemberOfClass: 能夠判斷出對象是否為某個特定類的實例。
isKindOfClass: 能夠判斷出對象是否為某類或其派生類的實例。
比較“類對象”是否等同,要用“==”操作符
原因在于,類對象是“單例”(singleton),在應(yīng)用程序范圍內(nèi),每個類的class僅有一個實例。
即使能這樣,我們也要盡量使用類型信息查詢方法
因為類型信息查詢可以正確處理那些使用了消息傳遞機制的對象。
比如說,某個對象可能會把其收到的所有選擇子都轉(zhuǎn)發(fā)給另外一個對象。
這樣的對象叫做“代理”(proxy)。
通常情況下,如果在此種代理上調(diào)用class方法,那么返回的是代理對象本身,而非接受的代理的對象所屬的類。
若是使用“isKindOfClass:”這樣的類型信息查詢方法,那么代理對象就會把消息轉(zhuǎn)給“接受代理的對象”。
也就是說,這條消息的返回值與直接在接受代理的對象上面查詢其類型所得的結(jié)果相同。
class方法:返回的是發(fā)起代理的對象的類
isKindOfClass方法:返回的是接受代理的對象的類
【要點】
1.每個實例都有一個指向class對象的指針,用以表明其類型,而這些class對象則構(gòu)成了類的繼承體系。
2.如果對象類型無法在編譯期確定,那么就應(yīng)該適用類型查詢方法來探知。
3.盡量使用類型信息查詢方法來確定對象類型,而不要直接比較類對象,因為某些對象可能實現(xiàn)了消息轉(zhuǎn)發(fā)功能。