IOS -執行時 (消息傳遞 )

一 函數調用概述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 ,它事實上是方法的映射表。

  如下是objc_method_list的結構
 struct objc_method_list {
    struct objc_method_list *obsolete                        
    int method_count                                         
    struct objc_method method_list[1]                       
 }


在objc_method_list中包括一個objc_method結構體
如下是objc_method的結構體
struct objc_method {   
       SEL  method_name 
char *method_types 
       IMP method_imp 
}  

   objc_method用來表明一個方法。其包括一個方法 SEL – 表示該方法的名稱,一個types – 表示該方法的參數,一個 IMP - 指向該方法的詳細實現的函數指針。

 對於每個參數如下將詳細說明。性能

     
      函數映射表的大體狀況例如如下圖所看到的



  2.SEL (An opaque type that represents a method selector)

     被定義爲 typedef struct objc_selector *SEL 
  文檔中並無透露objc_selector是什麼東西,但提供了@selector指令來生成:


      Objective-C 在編譯的時候,會依據方法的名字,生成 一個用來區分這種方法惟一的 ID ,這個 ID 就是  SEL 類型的。

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就是同樣的。指針


           說的通俗點。SEL就是一個函數標識,該標識是編譯器依據其函數聲明原型生成的。那假設兩個不一樣的類假設有一樣的函數聲明的話會生產一樣的ID(Objective-c 是不支持在類內函數重載的),那如何進行區分呢?請繼續往下看。

  3.IMP ( A pointer to the function of a method implementation)

       被定義爲typedef id (*IMP)(idSEL, ...)   
     IMP是一個函數指針,它指向的函數第一個參數實例變量的地址,即接受消息的對象的地址(receiver),第二個參數是SEL要調用的方法、第三個蠶食是函數參數,它是一個不定參數。函數的返回值爲id類型。
     IMP 是消息終於調用的運行代碼,該是方法是真正的實現代碼 。咱們可以像在C語言裏面同樣使用這個函數指針。

     - (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);     
     }

    - (IMP)methodForSelector:(SEL)aSelector 函數的做用是經過SEL生成的ID來查找和定位函數的實現地址。
    MyPrint(self,@selector(Print:),@"Hello World ); 調用MyPrint函數指針所指向的函數。參數分別爲receiver,SEL和要傳遞給函數的參數。
      
   經過上面的樣例,咱們明確了經過函數的第一個參數receiver可以區分不一樣類的函數聲明一樣的函數。


四 Objective-c消息傳遞

經過上面的一層層剖析和前一節有關類對象的解說,可能你大概明確了Objective-c中消息的傳遞方式了。

  首先,編譯器依據函數聲明生成一個惟一函數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, 同一時候接收消息不定參數列表。

    2.objc_masSend 經過 receiver中的isa找到類對象,從而找到 SEL 相應的方法實現 IMP。注:因爲不一樣的類對同一方法可能會有不一樣的實現,因此找到的方法實現依賴於消息接收者(receiver)。
如下再作一下具體消息傳遞過程:
                           
                           
 
   
 正因爲有像CRuntimeClass和object_class這些類類型的存在才使得它們擁有了執行識別。動態建立。序列化等機制。


      下一節將對消息傳遞作進一步的深層次探究。

相關文章
相關標籤/搜索