2012-07-16 43 views
5

通過調用isKindOfClass檢查類的類型是否更合適:或者通過僅檢查它是否支持您通過respondsToSelector查找的方法來執行「duck typing」方法:?Objective-C:檢查類的類型,最好使用isKindOfClass或respondsToSelector?

這裏是我想的,兩種方式編寫代碼:

for (id widget in self.widgets) 
{ 
    [self tryToRefresh:widget]; 

    // Does this widget have sources? Refresh them, too. 
    if ([widget isKindOfClass:[WidgetWithSources class]]) 
    { 
     for (Source* source in [widget sources]) 
     { 
      [self tryToRefresh:source]; 
     } 
    } 
} 

或者:

for (id widget in self.widgets) 
{ 
    [self tryToRefresh:widget]; 

    // Does this widget have sources? Refresh them, too. 
    if ([widget respondsToSelector:(@selector(sources))]) 
    { 
     for (Source* source in [widget sources]) 
     { 
      [self tryToRefresh:source]; 
     } 
    } 
} 
+0

檢查這個線程http://stackoverflow.com/questions/4913055/iphone-is-using-iskindofclass-considered-bad-practice-in-any-way – 2012-07-16 18:37:07

+0

需要注意的是,在一般情況下,動態不鼓勵檢查班級的類型。委託模式之外的選擇器響應也一樣。 – bbum 2012-07-16 19:57:47

回答

2

檢查可能是一個警告,您即將做出一個hackish解決方案。小部件已經知道他的課程和他的選擇器。

所以第三個選擇可能是考慮重構。將此邏輯移至[widget tryToRefresh]可能會更清晰並允許將來的小部件實現額外的幕後邏輯。

+0

所有好的答案,但這一個,對我來說其實是正確的。我能夠重新執行並徹底擺脫這些代碼! – 2012-07-17 18:36:06

6

這要看情況!

我的經驗法則是,這僅僅是爲了我,還是將它傳遞給其他人?

在你的例子中,respondsToSelector:沒有問題,因爲你只需要知道你是否可以發送消息的對象,所以你可以對結果做些什麼。這個班並不是那麼重要。另一方面,如果您要將該對象傳遞給其他代碼段,您不一定知道它將要發送的消息。在這些情況下,你可能會投射物體以傳遞它,這可能是你在投射它之前檢查它是否真的isKindOfClass:的線索。

要考慮的另一件事是歧義; respondsToSelector:告訴你一個對象會響應一條消息,但是如果該對象返回一個不同於你期望的類型,它可能會產生一個誤報。例如,一個對象,聲明的方法:當您嘗試在一個for循環中使用它的返回值

- (int)sources; 

會通過respondsToSelector:測試,但隨後產生異常。

這種情況發生的可能性有多大?這取決於你的代碼,你的項目有多大,有多少人正在編寫針對你的API的代碼等等。

5

它稍微更習慣使用目標C使用respondsToSelector:。目標C具有高度的動態性,因此您的設計時間對類結構的假設可能不一定在運行時保持水分。 respondsToSelector:通過給你一個查詢類的最常見原因的快捷方式來獲取它 - 它是否執行一些操作。

一般來說,如果圍繞幾個同樣吸引人的選擇存在歧義,那麼請注意可讀性。在這種情況下,這意味着思考意圖。你關心,如果它是特別是WidgetWithSources,或者你真的只是在乎它有一個sources選擇器?如果是後者,則使用respondsToSelector:。如果前者可能在某些情況下使用isKindOfClass.可讀性,則表示您不要求讀者在WidgetWithSources的類型對等和需要調用sources之間建立連接。 respondsToSelector:爲讀者提供了連接,讓他們知道您的實際意圖。這是對你的程序員的一種善意。

編輯:@ benzado的答案很好地吻合。

3

從@Tim & @benzado很好的答案,這裏是對主題的變化,先前覆蓋2箱子第一:

  • 如果在某些時候,你有沒有可能有不同類的引用,並需要他們不同的是,這可能是isKindOfClass:的一種情況。例如,顏色可能存儲在首選項中,作爲NSColorNSData序列化或具有其中一個標準名稱的NSString值;獲取NSColor的值在這種情況下isKindOfClass:上的對象返回可能是合適的。
  • 如果你有一個類的引用,但不同版本它隨着時間的推移支持不同的方法,然後考慮respondsToSelector:例如,許多框架類在OS的更高版本中添加新的方法,Apple的標準建議是檢查對於使用respondsToSelector:(而不是OS版本檢查)的這些方法。
  • 如果你有不同類別的參考,如果他們堅持一些非正式協議那麼你正在測試:

    1. 如果是這樣的代碼,你控制,你可以切換到正式協議然後使用conformsToProtocol:作爲測試。這具有測試類型而不僅僅是名稱;否則
    2. 如果是這樣的代碼你不用管,然後使用respondsToSelector:,但我們知道這是測試具有相同的方法存在,不在於它採用相同類型的參數