理解 objc_msgSend 的角色

對象調用方法,這個在Objective-C裏面叫做傳遞信息(passing a message)。信息有名稱,有方法,接收參數,還可能有返回值。

由於Objective-C是C的一個延展,那麼我們首先來看一下C語言中的函數是怎麼一回事兒。

C語言中的函數調用被稱爲static binding,(靜態or靜止)綁定;意味着被調用的函數在編譯時知道。

#import <stdio.h>

void printHello(){

printf("hello");

}

void printByebye(){

printf("byebye");

}

void doOneThing(int type){

if(type==0){

printHello();

}else{

printByebye();

}


}

上述代碼在編譯的時候,printHello與printByebye都是知道的,編譯器發出指定,直接來調用函數。 這些函數的地址已經被有效的硬編程在這些指令中。

換一種方式,如下展示:

#import <stdio.h>

void printHello(){

printf("hello");

}

void printByebye(){

printf("byebye");

}

void doSomething(int type){

void (*func)();

if(type==0){

func=printHello;

}else{

func=printByebye;

}

func();

}

如上所示,在這裏,動態綁定被使用上了,因爲要調用哪個函數是不知道的;只有在 runtime時。


上述兩種情形有何區別呢?

編譯器發出指令:

1.在第一種情形下,函數會在 if 和else 語句中都被調用。

2.在第二種情形下,函數只會被調用一次,付出的代價僅是讀取這個函數的地址,而不用將其硬編碼。


動態綁定是一種機制, 方法被調用,當一個信息傳遞給了一個object.  所有的方法都是,對於特定的信息哪一個方法被調用,完全決定於runtime;甚至可以改變,這一機制讓Objective-C 真正意義上dynamic.

如下所示:

id returnValue=[object  messageName: parameter];

object :接收者 (信息的接收者)

messageName:parameter  (方法selector與參數結合) 這個被稱爲一個信息。


當看這個叫信息時,編譯器將其轉化成標準的C函數,objc_msgSend:

void objc_msgSend(id self,SEL cmd,...)


這是一個可變的函數,接收不同個數的參數。第一個參數是 消息的接收者,第二個參數方法,後面的參數就是 原來信息中的參數形表,按照其出現的順序依次羅列。

上面的:

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

objc_msgSend函數調用正確的方法,取決於接收者的類型和方法。 爲了做到這些,objc_msgSend首先會在接收者的方法列表中去找這個方法,如果找到,將會跳到這個方法的實現中去;如果沒有找到,objc_msgSend會一路向上找其父類是否有這個方法。如果還是沒有找到方法,message forwarding kicks in. 哈哈!item 12


看起來好像是當一個方法被調用時,有很多事情要做。幸運地是,objc_msgSend 會緩存這個結果,所以在未來給相同的類發消息時,會執行地很快。

fast path -----會慢一些------  statically bound function 調用;

但是如果cach下來了,比靜態綁定的函數慢不了多少。

實際情況下,信息調用派遣在一個應用中並不是瓶頸。如果它是的話,那麼我們還不如去直接用C語言去寫呢,將oc 對象的任何狀態傳遞給它。


前述方法僅適用於某些信息。額外的函數 暴露給了 Objective-C的  runtime 來去處理某些情況:

objc_msgSend_stret

對於某些信息,返回一個struct(結構體)。 這個函數只能處理 適應CPU 寄存器類型 的返回值。 

        objc_msgSend_fpret

對於那些返回值爲浮點數的信息。一些architectures需要在函數調用之間對浮點寄存器進行特殊處理,意味首objc_msgSend不是足夠好。 這個函數存在的意義是:處理這些奇怪的事情,如x86上面。

        objc_msgSendSuper

 如果將信息傳給了父類,例如:[super message:parameter]; 


在上面,我暗指了 objc_msgSend

//todo! 

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