2011-07-16 26 views
3

我正在比較不同的編程語言和開發平臺。 objective-c和其他語言之間的一個重要區別是,它使用選擇器和消息,所以每次調用objc_msgSend時,都要跨越共享庫的邊界,因此引入了可測量的開銷,並且爲objc_msgSend增加了額外的開銷(在緩存的情況下很少)內部功能,像這裏解釋: http://www.mulle-kybernetik.com/artikel/Optimization/opti-3.html 我不是專家,所以我不得不相信這篇文章,在這個論壇上找到。 在官方Apple指南中,我發現「點語法」只是「語法糖」,即使用了相同的方法調用機制。 問題:我想知道,純粹的調用是在類實例內部執行的,在這種情況下調用objc_msgSend是一種浪費。那就是當一個類實例的方法從同一個類實例的方法中被調用時。 謝謝objective-c:方法仍在調用選擇器或純調用的類中調用?

回答

1

所有Objective-C方法調用使用obj_msgSend。這是因爲代碼不知道self的實際類。即:它可能是另一個實現的子類,或者甚至是由遠程機器通過xmlrpc實現的方法的代理。如果你知道你要經常發送消息X到對象Y,你可以通過抓取給定對象的選擇器的實現來自己優化。

+0

你指的是IMP嗎?對於課堂內的每一個電話來說,這是多麼糟糕的事情。然而,編譯器是否能夠理解實例在編譯時調用自己?很奇怪。我的意思是,我沒有使用選擇器語法來調用同一個實例的方法,是嗎? – P5music

+1

@ P5music:即使在C++中,從類的成員函數的實現中調用類的虛方法,也會通過虛函數表。在Objective-C中,每個方法調用都是虛擬的。所以它通過'objc_msgSend'設施進行調用。別擔心,蘋果知道'objc_msgSend'是絕對關鍵的,所以他們付出了很大的努力來調整它,使用手寫彙編和大量的黑客手段。 – Yuji

4

考慮這種情況在一個假設的OOP語言:

class A { 
    say_something(){ 
     print("A!") 
    } 
    do_something(){ 
     say_something() 
    } 
} 

class B : extends A { 
    say_something(){ 
     print("B!") 
    } 
} 

現在,假設你有B一個實例,並調用do_something

B b; 
b.do_something(); 

應該b打印AB?如果在執行do_something時調用vtable(使用C++)或obj_msgSend(使用Obj-C),它將打印B,但如果編譯器決定調用同一類中的方法,則應調用方法在同一個類中,它將打印A

哪一個取決於具體情況。因此,在C++中,您可以通過標記成員函數virtual來進行選擇。在Objective-C中,每種方法都是虛擬的。

因此,即使在C++中,您所建議的優化也不會對虛擬方法進行。如果沒有虛擬方法,我不會說一種適當的OOP語言。

無論如何,現在您可能擔心它會降低Obj-C應用程序的性能。蘋果知道危險,所以他們有很多很多的優化。例如,在最近的運行時中,objc_msgSend位於固定地址,因此您不必首先瀏覽共享庫邊界。

Mulle-Kybernetic的文章也很好,但也注意到它很過時:十年前它就是高潮,這在這個行業是一個史前時代。您可以閱讀關於objc_msgSendbbum's blog postsHamster's blog posts中實施的最新優化。

如果您正在編寫管理UI的代碼,請使用標準消息傳遞(即,幕後的objc_msgSend)完全夠用了。它甚至能在移動設備上非常流暢地運行!因此,不要通過獲得IMP等來進行不成熟的優化,直到在測量代碼的性能之後它變得絕對必要爲止。

如果你正在編寫一個涉及數萬個粒子移動的計算密集型代碼,是的,我建議不要使用Obj-C消息框架。在這種情況下,只需簡單地編寫一個C代碼(可以在Objective-C中使用)或C++代碼(可在Objective-C++中使用)。

0

它仍然通過objc_msgSend和變體使用動態分派。

理想情況下,將爲objc類型生成與JIT類似的內容。

不像objc,C++編譯器可以使用靜態調度呼叫到C++被標記虛擬當它可以確定類型類型。

無論如何,有很多方法可以優化 - 你可以先用C++實現,然後使用objc,它真的很方便......但我不確定你到底想要完成什麼。