標籤:
在 Objective-C中id類型的對象可以轉換為任何一種對象,有點類似與void*指標類型的作用。下面簡要介紹一下id類型。
id標誌符:通用物件類型。id類型是一個獨特的資料類型,可以轉換為任何資料類型,即id類型的變數可以存放任何資料類型的對象。這是為什麼呢?還是從OC的內部實現機制上來分析吧!
在內部處理上,id類型被定義為指向對象的指標,這可以從id的定義中看出。id在objc.h中的定義為:
typedef struct objc_object {
Class isa;
} *id;
而Class為typedef struct objc_class *Class,即Class為struct objc_class的指標別名,而objc_class在runtime.h中的定義為
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;
從上面的代碼看出,id是指向objc_object的一個指標。那麼它為什麼可以指向NSObject對象呢?還是看NSObject的定義吧!
@interface NSObject <NSObject> {
Class isa;
}
可以看出NSObject只有一個Class對象isa,而objc_object也是只有一個Class對象isa,可以看成兩者等價(不知道對不對?)。所以id是一個一個比較靈活的對象指標,並且是一個指向任何一個繼承了Object(或者NSObject)類的對象。而在cocoa的開發環境裡,NSObject是所有類的根類。所以id可以指向任何一個cocoa的合法對象。
從上面的程式碼分析可以看出,id實際上是一個指向NSObjec對象的執行個體變數的指標,即id和void*並非完全一樣。
PS:id和IMP標誌符之間的關係:
id:是一種資料類型;
IMP:指向返回id類型值的方法的指標,而且指向的方法帶有self和selector對象作為第一個參數。它是一種C類型,可以認為是一種函數指標。其英文解釋:IMP is a C type referring to the implementation of a method, also known as an implementation pointer. It‘s a pointer to a function returning id, and with self and a method selector (available inside method definitions as the variable _cmd) as the first arguments。
其使用方法為:id (*IMP)(id, SEL, ...);(SEL為選取器selector的一個類型,選取器就是指向方法的一個指標)
對於NSObject對象,你可以這樣來獲得一個給定方法的IMP:
IMP imp=[obj methodForSelector:@selector(message)];
對於任意的對象object,
IMP imp=[obj methodFor:@selector(message)];
Objective-C id類型實現原理