2011-04-11 84 views
5

如何強制編譯器從一組共享相同名稱的方法中選擇所需的方法?兩個類方法,相同名稱,不同簽名:如何強制編譯器使用預期的方法?

/* Use +[MyClass port](UInt16 (*)(id, SEL), 
* not +[NSPort port](NSPort *(*)(id, SEL)). */ 
UInt16 port = [[self class] port]; 

我有一個Objective-C類與類方法:

+ (UInt16)port; 

NSPort有一個便利的構造函數的簽名衝突與此:

+ (NSPort *)port; 

發送+port我的課結果在編譯器中警告:

UInt16 port = [[self class] port]; 
    W: Multiple methods named '+port' found 
    W: Using '+(NSPort *)port' 
    W: Also found '+(UInt16)port' 

失敗:編譯器選擇了錯誤的方法簽名。

類型推斷失敗:使用[[(MyClass *)self class] port]不會使用正確的方法將其拼合到一起。

ETA:這裏是我用現在的解決方法:

#import <objc/runtime.h> 

Class c = [self class]; 
SEL s = @selector(port); 
typedef UInt16 (*PortIMP)(id, SEL); 
PortIMP MyClassGetPort = (PortIMP)class_getMethodImplementation(c, s); 
UInt16 port = MyClassGetPort(c, s); 

正是在這種良好:

  • 它處理正確地分配給任一子類實現。
  • 它僅限於實現文件,所以這個醜陋不會造成任何人,除了實施者。

這是壞的,它不會幫助任何其他人想要調用該方法。

+0

MyClass&NSPort之間有什麼關係? – kikito 2011-04-11 16:15:15

+0

@egarcia:沒有關係。 'NSPort'頭由Foundation框架導入。 – 2011-04-11 16:21:06

回答

2

爲什麼不只是重命名方法? (跛腳,我知道)你可能會爭辯說一個名爲「port」的方法應該返回一個port對象(這就是NSPort所做的),並且如果你想返回一個原始的「端口號」,你可以稱之爲「 portValue「(a la」intValue「,」longLongValue「等)。

+0

重命名該方法並不能解決問題,它避免了這個問題。此外,對Apple框架使用情況的調查證實了我的直覺,即我們的直覺認爲,返回整數類型的'port'方法完全是慣用的:' - [NSURL端口]返回'NSNumber',但是 - [MIDINetworkHost端口]返回'NSUInteger', ' - [NSNetService port]'返回'NSInteger',因此它可以使用-1來表示「未解析」,並且' - [NSMachPort machPort]'返回'uint32_t'。這是3個以「port」結尾的方法,返回標量類型,而返回1個對象類型。 – 2011-04-11 17:43:06

+0

是的,這是避免了這個問題(因此「跛腳,我知道」評論)。您引用的其他示例可以通過嚴格鍵入變量來避免(因爲它們都是實例方法)。你的問題源自這是一個* class *方法,並沒有出現將'id'強制轉換爲特定'Class'的方法。 – 2011-04-11 17:47:13

+0

選擇此答案是因爲它是最易維護且無摩擦的解決方案。根本問題似乎是Obj-C將類視爲面向對象共和國中的二等公民。 – 2011-04-14 19:27:29

3

有趣......這似乎不是一個明顯的解決方案。

你可以使用一個協議來聲明你需要的方法,例如

@protocol MyClassProtocol 
@optional 
- (UInt16)port; 
@end 

然後做

UInt16 port = [(id <MyClassProtocol>)[self class] port]; 

不漂亮,但它確實工作。

+0

我想你想要的是'+(UInt16)端口;'。 – 2011-04-11 16:22:20

+0

不,它確實需要是' - (UInt16)port',因爲你告訴編譯器_class_對象有什麼方法。 – alastair 2011-04-11 16:26:05

+0

感謝您的建議。這可能起作用,這是對我以前所做的改進。缺點是它污染了全局協議名稱空間。這也很醜。我覺得這就像是迫使每個人都在觀看標題,觀看Obj-C語言和GCC編譯器之間的大聲說他說的話。 – 2011-04-11 16:33:36

0

只要做到[(MyClass*)[self class] port]。這將在所有情況下都能正常工作,而且是最簡單的方法。

+3

不,這不起作用。我也有這個想法,但是編譯器最終想要一個' - [MyClass port]'方法而不是'+ [MyClass port]'方法,它仍然會產生警告。 – 2011-04-11 16:46:32

+0

奇怪的是,我不能說我之前遇到過這種情況。 – 2011-04-11 18:21:06

+0

問題是它是_class_方法。 '[(MyClass *)[self class] port]'告訴編譯器'[self class]'是類MyClass'的一個對象,這是不正確的。不幸的是,沒有語法來表達'[( *)[self class] port]',這就是爲什麼你需要使用協議或者用正確的方法簽名聲明類。 – alastair 2011-04-12 11:21:51

相關問題