Objective-C之消息機制

話說2014年4月編程語言排行榜中Objective-C的使用比又增加了,看來IOS和MAX OS的開發者是真給力呀。

不過個人感覺用不了多久,IOS和Android的開發者收入就不會有那麼大的差異了,因爲從現在Android軟件的質量上來講已經有了質的提升。

(扯遠了,以上觀點純屬虛構,如有雷同,純屬巧合)

 

閒話少說,今兒個聊聊Objective-C的動態綁定。

“消息結構”(messaging structure)

說到動態綁定,就得先說一下Objective-C的“消息結構”(messaging structure)。

"消息結構"與“函數調用”(function calling)還是有很大不同的。

其關鍵不同在於:

  • 使用消息結構的語言,其運行時所應執行的代碼由運行環境來決定。      
  • 使用函數調用的語言,則由編譯器決定。

再通俗點說就是:

  採用消息結構的語言,不論是否多態,總是在運行時纔會去查找所要執行的方法。

   實際上,編譯器設置不關心接收消息的對象是否是何種類型。接收消息的對象問題也要在運行時處理,其過程叫做“動態綁定”(dynamic binding)。

 “動態綁定”(dynamic binding)

在解釋動態綁定之前,首先看兩段小代碼:

 代碼段1:

 1 #import <stdio.h>
 2 
 3 void A () {
 4     printf("A");
 5 }
 6 
 7 void B () {
 8     printf("B");
 9 }
10 
11 void callMethod (int value) {
12     if (value == 0) {
13         A ();
14     } else {
15         B ();
16     }
17 }

 

代碼段2:

#import <stdio.h>

void A () {
    printf("A");
}

void B () {
    printf("B");
}

void callMethod (int value) {
    void (*func)();
    if (value == 0) {
        func = A
    } else {
        func = B;
    }
    func();
}

下邊對以上的代碼段進行一下解釋:

從功能上來講,兩段代碼是一樣的,不多說(如果連功能都看不懂的話...咳咳...)

主要是聊一下這兩者的區別:

  • 第一段代碼是所謂的“靜態綁定”(static binding),也就是說,以上代碼在程序的編譯階段就能決定運行時所應該調用的函數。

   此時編譯器在編譯代碼的時候就已經知道程序中有A和B這兩個函數,並且將這兩個函數的地址硬編碼子指令之中。

  • 第二段代碼是所謂的“動態綁定”(dynamic binding),也就是說,要運行的函數,只有在運行階段才能決定調用的是A函數還是B函數。

   此時編譯器只能等到運行時纔會把調用的函數地址硬編碼在指令中。

 

如何實現動態調用

 拿這段代碼來舉例:

  id returnValue = [object messageName:parameter];

如果用“函數調用”的思想來讀這段代碼的話就是:

  調用object對象的messageName方法,並且傳遞參數parameter。調用此方法之後返回值爲returnValue。

但是!!!Objective-C是“消息結構”!!!

所以正確的理解方式應該是這樣:

  • returnValue是返回值,這一點與“函數調用”並沒有什麼區別。
  • object是消息的“接收者”(receiver),也就是我們給object對象發送了一個消息。
  • messageName,是“選擇子”(selector),注意messageName並不是message。那位童鞋問那message是哪個?彆着急,咱後邊會說。
  • parameter是參數,與“函數調用”沒有什麼區別。

前邊說messageName並不是我們所理解的message,爲什麼這麼說呢?哦~~~?

這麼說吧,如果我告訴你去北京找一個叫張三的人,那你肯定就瘋了。

但是,如果我告訴你去北京**區**街**小區**棟**室的張鐵錘家的張三,是不是很容易呢?

在“消息機制”中,messageName就相當於張三,而object就相當於balabala家的張鐵錘。

所以說,“消息”(message)並不是“選擇子”(selector),而是“選擇子”(selector)與“接收者”(receiver)的組合。

 

怎樣傳遞消息

當編譯器收到"id returnValue = [object messageName:parameter]"這條消息的時候,就會將其轉換爲C語言函數調用(因爲Objective-C的底層調用的是C語言),調用的這個函數就是消息傳遞機制中的核心函數,叫objc_msgSend。

objc_msgSend函數的原型爲:void objc_msgSend(id self, SEL cmd, ...)

  • id self 代表消息的接收者
  • SEL cmd 代表選擇子
  • ... 代表參數,同時也說明了這是個參數個數可變的函數。

如果將"id returnValue = [object messageName:parameter]"轉換爲C語言代碼的話就應該這麼寫:

id returnValue = objc_megSend(object, @selector(messageName:), parameter);

objc_megSend函數要做的就是根據接收者與選擇子的類型來調用適當的方法。

具體怎麼調用的,怎麼提高調用的效率,balabala,還是大家有時間自己研究一下吧。

另外附上咱家的微信公衆號的二維碼,沒事兒可以掃掃哈。

有啥事兒大家可以隨時留言交流。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章