1. 類,是一個模板,定義了成員(數據),方法(函數)和關係(繼承,接口)。
可以簡單理解爲一個結構體C,裏面定義了這些信息。
對象,也是一個結構體,只是裏面擁有一個類型信息的指針,然後該指針的值等於類型信息結構體的地址。對象的類型不同,也就是其類型指針的值的不同,所有類型的數據結構應該是一致的。
--->
@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}
--->
typedef struct objc_class *Class;
--->
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#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;
以上,也可以一窺Object對象的數據結構了。
2.方法信息,對於OC中的方法,乍看起來比較奇怪,其實這樣做是合理的。從數據結構上可以看到,可以猜測其實現最後是由OC編譯器翻譯成了了C語言的進行編譯鏈接成可執行程序的,那麼C裏面只有函數。其形式大致是之類的形式之類的形式,
int func( int a, double b, char *s );
那麼OC方法是,
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
要實現方法的重載,就必須有方法的簽名,這裏可以根據以上,由OC編譯器由以上方法名翻譯成兩部分:
(1)方法簽名,類似與一個字符串一樣的東西,[performSelector:withObject:withObject:],其實應該還要帶上參數的類型信息。反射機制裏面由^$#之類的類型替代符符號等。
(2)方法實現(傳統的C函數)int performSelector_...( SEL a,....)之類的C語言函數。
配上合適的(key,value)之類的數據結構,就可以實現面向對象了,這樣每次調用函數的時候,OC編譯器根據函數名稱生成方法簽名的key,然查找到函數實現。就可以了。還有一種可能的實現是,靜態編譯直接調用,那麼可以直接根據規生成函數名稱,然後由OC編譯器生成函數實現。比如以上可以有,
void *performSelector_withObject_withObject( SEL del, ....){ ... return ...}的函數名稱,然後實現該函數即可。
多態的實現,如果對象結構的類型信息中含有父類的指針,那麼就可以通過該類對象開始向父類按照簽名逐級查找就是多態類。因爲對象的引用畢竟只是一個指針而已,而對象類型信息的數據結構,肯定是像一個鏈表一樣的數據結構,所以查找肯定也是從該類開始向父類逐級查找,所以多態是天生自然支持的。
注意,以上的理解也是一個大致的理解,只是根據自己已有的經驗和知識進行的一個總結,並沒有太糾結與實際情況。
3. 題外話
因爲C是最接近操作系統結構和運行原理的語言,所以,一些必須的元素是必須要有的,比如方法最後還是函數,函數的話,肯定必須有函數地址,函數參數等。所以,各類語言,個人覺得多數是一個語法糖一樣的東西,然後根據不同目的出發點,設計出合理的數據結構,函數調用方式,配上新的語法,然後根據這些來編寫一個編譯器,就可以推出很多新的語言,比如OC,這些都是一個量變引起質變的過程。
每種新的語言都是一種有目的重新設計。但是,最後都是通過各種橋,翻譯成裏彙編等可以讓機器運行的語言(彙編,01010110111...)。條條道路通羅馬。每條路的盡頭其實都是同一個目的地。
個人覺得,編程可以不用C,但是必須還是得了解的,萬變不離其宗。