2012-07-07 60 views
2

對於Objective-C來說很新穎,但是我遇到了似乎很常見的情況:我希望ClassA要求ClassB在只有ClassB的對象上執行方法知道(也使用ClassA未知的方法)。Objective-C:performSelector:vs forwardInvocation:

我找到了這樣做的方法有兩種:performSelector:forwardInvocation: - 但我想了解更多信息,鞏固我的每一個的理解。我發現這記在蘋果開發者文檔:

的aSelector參數[中performSelector:]應該明確,它沒有 參數的方法。對於返回除對象之外任何內容的方法,請使用NSInvocation。

..does這意味着,隨着開頭的方法 - (ID)METHODNAME將使用performSelector:,而說- (INT)nonObjectMethodName將使用forwardInvocation:

還有什麼方法返回(void)?或返回非id對象的方法,例如(NSString)

+0

注意-performSelector:withObject:同樣存在。 – NSResponder 2012-07-08 09:28:30

回答

6

-forwardInvocation:被用作消息轉發機制的一部分。不要擔心郵件轉發,因爲它只能被代理對象使用,並且賠率很好,您永遠不需要使用它並知道您正在使用它。

-performSelector:假定郵件的返回類型是id或兼容,並且如果它是用來發送一個消息返回類型是不同的(例如,比指針更廣泛諸如long long在32位系統中,以便並不安全,或通過不同的寄存器/地址返回,如float或大struct

如果你想間接地發送這樣的消息,你可以創建NSInvocation類的實例,然後將其發送-invoke。然後將返回值存儲在調用對象中,並可以通過它訪問。在這種情況下,您從未使用過-forwardInvocation:

一般來說,如果您發現自己使用-performSelector:,那麼您可能正在處理反模式。在這種情況下,您嘗試發送一條消息,ClassA未正式知道。另一種解決方案是公開這些私有方法。


如果您同時擁有ClassAClassB,您可以ClassB,包括您要使用的私有方法創建一個「私人」的標題。如果其他人(例如Apple)擁有ClassB,則您正在處理未公開的API,並且可能需要尋找其他方法,因爲Apple會拒絕使用此類API的應用程序。

要創建專用標題,請進入Xcode並創建一個新的標題文件。將其命名爲「ClassB + Internal.h」或「ClassB + PrivateMethodsForMeOnly.h」。把它當作你的項目的私有項目 - 沒有人會使用它,除非他們是ClassB的同行(同一個子項目或庫或組件)。在這個新的報頭,添加以下內容:

#import "ClassB.h" // so we get the original class definition 

@interface ClassB (PrivateMethodsForMeOnly) 
- (double)someMethod; 
- (const struct low_level_c_type_t)otherMethod:(int)i; 
// etc. etc. etc. 
@end 

而且在ClassA.mClassA.h,除非你想公開這些方法大家誰使用ClassA!)添加下面一行在包括部分:

#import "ClassB+PrivateMethodsForMeOnly.h" 

ClassA此後將有機會獲得在新的類別的那些方法。

+1

+1私人頭文件跳舞。 – Peres 2012-07-07 23:50:52

+0

很好的解釋。 – Tatvamasi 2012-07-07 23:52:54

+0

當您構建框架或圖書館時,私人標題舞蹈是一件美麗的事情。在一個單獨的項目中,這有點愚蠢,因爲所有的類都可以完全訪問對方。儘管如此,強化這種剛性卻迫使你更多地考慮你的階級層次,這絕不是浪費時間。 – 2012-07-07 23:54:09

0

好的,這是幾個問題。

首先,忘記「forwardInvocation」 - 這幾乎是你唯一需要做的代理對象的方法。

調用是使用[NSInvocation invocationWithMethodSignature ...]創建的,然後用選擇器,參數和目標對象填充,最後您只需「調用」它。這就是你可以發送(甚至存儲)任何方法調用的方式。

performselector存在若干變化,其中一些需要的參數,調用它的延遲之後,或運行於另一個線程的方法。這是一個更「直接」的調用 - NSInvocation是一個對象,可以像任何其他對象一樣保留,直到需要它爲止,而「performselector」幾乎可以立即運行該方法。

至於返回值,我通常堅持文檔所說的;如果它告訴我方法應該返回一個id我返回一個對象(任何對象指針都可以,所以NSString *很好,返回nil也可以,這幾乎涵蓋了'void'的情況),不是void而不是int。

另外,請記住,調用performselector是不是所有的常見;在大多數情況下,您只需在「[MyObject SomeMethod:SomeParameter];」中對該調用進行硬編碼。調用performSelector風格的方法適用於特殊情況 - GUI對象上的目標/動作是這樣一種情況,即要調用的選擇器存儲在對象中,因此顯然不能進行硬編碼。

0

-forwardInvocation:的目的是讓一個對象嘗試發送它不承認其他一些對象,而不是隻給了一個消息。 NSInvocation不僅包含選擇器,還包含消息的所有參數。 NSProxy使用它,但是如果我記得正確,我們在分佈式對象之前就有過它。這是實施「這個班級無法處理的一切」的授權的一種方式。

你應該閱讀section on message forwarding in the Objective-C docs.

相關問題