2011-09-21 27 views
1

我有以下方法:反思參數:id來決定它是否是一個類或協議

-(void)SomeMethod:(id)classOrProtocol; 

它將被稱爲像這樣:

[self someMethod:@protocol(SomeProtocol)]; 

或者

[self someMethod:[SomeClass class]]; 

在方法體內我需要確定是否| classOrProtocol |是:

任何類(類)或任何協議(協議)或任何其他

[[classOrProtocol class] isKindOfClass: [Protocol class]] 

導致(建立)錯誤:

Receiver 'Protocol' is a forward class and corresponding @interface may not exist

所以,我怎麼能知道從一個協議一個類別從其他任何?

回答

2

在Objective-C 2中(即除非您在OS X上使用32位運行時)Protocol被定義爲只是一個前向類,請參閱/usr/include/objc/runtime.h。真正的界面沒有任何聲明。您可以嘗試包括/usr/inlcude/objc/Protocol.h

#import <objc/Protocol.h> 

但被寫在那裏,沒有方法公開支持的Protocol一個實例。處理Protocol實例的唯一可接受的方法是使用運行時函數,在Objective-C Runtime Reference中給出。甚至沒有公開定義Protocol是否是任何東西的子類,甚至沒有說它實現了NSObject協議。所以你不能調用任何方法。

當然,您可以使用運行時的源代碼來查看發生了什麼。 Protocol繼承自Object(這是來自OpenStep NeXTSTep之前的剩餘部分),而不是從NSObject。因此,您不能使用NSObject衍生對象的熟悉方法,包括NSObject衍生對象的Class。請參閱Protocol.hProtocol.m的開源實現。如你所見,類Protocol本身不會做任何事情,因爲每個方法只會將self投射到protocol_t並調用一個函數。實際上,從函數_read_imagesobjc-runtime-new.mm中的其他人可以看出,當可執行文件和庫被加載並且從不使用時,對象的isa指針被手動設置爲

因此,不要試圖檢查id是否是Protocol或不。

如果你真的需要做到這一點,你可以用

id foo=...; 
if(foo->isa==class_getClass("Protocol")){ 
    ... 
} 

但是,嚴重的是,不這樣做。

+0

感謝您的全面回答。我在與依賴注入相關的代碼中使用這種方法,在這種情況下,我認爲這是有道理的。但也許我應該把它分成兩種方法。 – Undistraction

+0

在內部添加了更多信息。閱讀源代碼很有趣,謝謝你的好問題,1ndivisible! – Yuji

-1

這不是「無法確定它是類還是協議所導致的問題」。錯誤是由於缺少Protocol類的接口造成的。確保你在你正在測試參數類型的實現文件的頂部導入Protocol.m

您也可以嘗試使用NSClassFromString()函數,該函數將返回Class對象或nil。請注意,如果nil被返回,它並不意味着該參數是協議。這只是意味着它也可能是未定義的類!

還有一種方法NSProtocolFromString它返回適當的結果 - 協議協議和nil未定義的協議。

+0

感謝您的回覆。如果我嘗試導入「Protocol.m」(或「Protocol.h」),則會出現「文件未找到」錯誤。我也可以使用協議作爲參數類型在同一個文件中,而不需要任何導入。 – Undistraction

+0

對,我認爲這有點廢話,因爲Protocol是一個實際協議類型的類,它沒有Protocol。(h | m)文件。抱歉誤導你。 – Eimantas

相關問題