id是oc語言中一個獨特的數據類型。一種通用對象類型。可以轉換為任何數據類型,即id類型的變量可以存放任何數據類型的對象。
萬能指針,能指向操作任何OC對象 id ==NSObject *
這是為什么呢?還是從OC的內部實現機制上來分析吧!
在內部處理上,id類型被定義為指向對象的指針,這可以從id的定義中看出。id在objc.h中的定義為:
1 typedef struct objc_object { 2 Class isa; 3 } *id;
而Class為typedef struct objc_class *Class,即Class為struct objc_class的指針別名,而objc_class在runtime.h中的定義為
1 struct objc_class { 2 Class isa; 3 #if !__OBJC2__ 4 Class super_class OBJC2_UNAVAILABLE; 5 const char *name OBJC2_UNAVAILABLE; 6 long version OBJC2_UNAVAILABLE; 7 long info OBJC2_UNAVAILABLE; 8 long instance_size OBJC2_UNAVAILABLE; 9 struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; 10 struct objc_method_list **methodLists OBJC2_UNAVAILABLE; 11 struct objc_cache *cache OBJC2_UNAVAILABLE; 12 struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; 13 #endif 14 15 } OBJC2_UNAVAILABLE;
從上面的代碼看出,id是指向objc_object的一個指針。那么它為什么可以指向NSObject對象呢?還是看NSObject的定義吧!
1 @interface NSObject <NSObject> { 2 Class isa; 3 }
可以看出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)];