一 函數調用概述objective-c
Objective-C不支持多重繼承(同Java和Smalltalk),而C++語言支持多重繼承。編程
Objective-C是動態綁定,它的類庫比C++要easy操做。安全
Objective-C在執行時可以贊成依據字符串名字來訪問方法和類。還可以動態鏈接和加入類。 C++ 跟從面向對象編程裏的Simula 67(一種早期OO語言)學派,而Objecive-C屬於Smalltalk學派。Simula 67學派更安全。因爲大部分錯誤可以在編譯時查出。 在C++裏,對象的靜態類型決定你可否夠發送消息給它,而對Objective-C來講。由動態類型來決定。數據結構
Objective-C比C++ 更強調類型的動態性,儘管犧牲了一些運行性能。但由於模型清晰,而犧牲的這些性能可以在今天由更先進的編譯技術來彌補。
ide
二 消息的產生函數
在Objective-c中消息一直到執行時才幹綁定到相應的函數:
[reveiver message];
編譯器在處理時會將上面的表達式處理稱如下這樣的形式:
objc_msgSend(receiver,selector);
假設方法有多個參數的時候會處理成如下這樣的形式:
objc_msgSend(receiver,selector,arg1,arg2。…….);
現在咱們知道了在Objective-c中函數調用都會被編譯器進行預處理,調用obj_msgSend函數進行消息的發送。這裏需要弄明確的selector是什麼東東?receiver是怎麼樣來調用指定的函數的,它在背後是如何實現的?如下將逐一解釋。 post
三 類對象中與消息有關的結構
首先看一下與消息傳遞有關的幾個數據結構和數據類型。
1. struct objc_method_list **methodLists
在上一節中知道在類對象objc_class中有一個結構體 struct objc_method_list **methodLists ,它事實上是方法的映射表。
struct objc_method_list { struct objc_method_list *obsolete int method_count struct objc_method method_list[1] }
在objc_method_list中包括一個objc_method結構體
struct objc_method { SEL method_name char *method_types IMP method_imp }
對於每個參數如下將詳細說明。性能
(A selector is the name used to select a method to execute for an object, or the unique identifier that replaces the name when the source code is compiled. A selector by itself doesn’t do anything. It simply identifies a method. The only thing that makes the selector method name different from a plain string is that the compiler makes sure that selectors are unique. )僅僅要方法的名字(包含參數序列)一樣,那麼它們的 ID都是一樣的。spa
就是 說,不管是超類仍是子類,不管是有沒有超類和子類的關係,僅僅要名字一樣那麼ID就是同樣的。指針
- (void) viewDidLoad { [super viewDidLoad]; //聲明一個函數指針 void (*MyPrint)(id,SEL,NSString*); MyPrint = ( void (*)(id,SEL,NSString*) )[self methodForSelector:@selector(Print:)]; MyPrint(self,@selector(Print:),@"Hello World"); } - (void) Print:(NSString*) str { NSLog(@"%@",str); }
首先,編譯器依據函數聲明生成一個惟一函數ID,每個實例變量的第一個成員是isa,它指向類對象,在類對象中保存有該類所擁有的方法列表,經過生成的的函數ID可以找到其相應的函數地址,從而調用函數。假設在當前類對象的函數映射表中沒有找到函數的話,就繼續搜索其父類中(每個類對象的super_class 存儲了父類的類對象地址),假設到達其根類仍是沒找到的話,會報執行時錯誤。 其步驟例如如下圖所看到的:
消息的成功傳遞依賴於兩個重要的要素,經過實例中的 isa指針找到實例所屬的類對象,而後經過類對象中的消息映射表找到所要調用的函數。
首先經過傳遞的selector參數找到消息映射表中的函數。而後調用函數,將實例的地址和參數傳遞給調用的這 個函數。最後返回返回值。
類類型的存在使objective-c擁有了執行時識別,動態建立,序列化等機制。
3.消息接收者對象(指向消息接收者對象的指針)以及方法中指定的參數傳遞給方法實現 IMP。
4.最後。將方法實現的返回值做爲該函數的返回值返回。
注:編譯器會本身主動插入調用消息函數objc_msgSend。咱們無須在代碼中顯示調用該消息函數。
五 消息傳遞小結
到這裏,咱們已經大體明確了Objective-c 中消息的傳遞的整個過程。事實上假設你熟悉MFC的話,你會發現Objective-c的執行時和MFC的RTTI挺像的。
下圖是MFC的執行時機制,CRuntimeClass至關於Objectiv-c的object_clas類對象,在CRuntimeClass中有指向基類函數的指針。與MFC不一樣的是object_class沒有相似與m_pNext_ClassMFC成員。
1.編譯器會將消息轉換爲對消息函數 objc_msgSend的調用,該函數有兩個基本的參數:消息接收者 receiver 和消息相應的方法ID,即SEL, 同一時候接收消息不定參數列表。
如下再作一下具體消息傳遞過程:
正因爲有像CRuntimeClass和object_class這些類類型的存在才使得它們擁有了執行識別。動態建立。序列化等機制。
下一節將對消息傳遞作進一步的深層次探究。