2010-10-17 34 views
2

我從「Objective C中的編程」中的示例中有一個名爲AddressCard的類,並且我實現了一個isEqual:方法。當重寫方法時嚴格與寬鬆輸入

在NSObject的這種方法的簽名使用弱類型的參數:

- (BOOL)isEqual:(id)anObject 

OTOH,書中的示例代碼使用嚴格類型:

- (BOOL) isEqual:(AddressCard *) aCard 

我不知道我充分了解編譯器在這種情況下所做的工作。我嘗試將AddressCard與NSString([aCard isEqual: @"Foo"])進行比較,期望運行時錯誤(如果系統使用我的方法)或系統會調用NSObject的IsEqual版本。

相反,我的方法被調用(即使參數是一個的NSString而不是AddressCard),並提出了一個異常時,我ISEQUAL:試圖打電話給AddressCard具體AA方法:

- (BOOL) isEqual:(AddressCard *) aCard { 
    if ([name isEqualToString: [aCard name]] && /*here I get the error*/ 
     [email isEqualToString:[aCard email]]) { 
     return YES; 
    }else { 
     return NO; 
    } 
} 

這是怎麼回事?在地球上如何將NSString傳遞給期望別的東西的方法?覆蓋它時是否改變方法的簽名?

回答

1

運行時通過其選擇器區分消息。所有具有相同名稱的方法都具有相同的選擇器。方法參數對選擇器沒有影響。在你的情況下,選擇器是isEqual:

這是蘋果的「的Objective-C編程語言」(重點煤礦):

消息傳遞程序只有經選擇訪問方法的實現,所以它把具有相同的選擇一樣的所有方法。它從選擇器中發現方法的返回類型及其參數的數據類型。 因此,除了發送給靜態類型接收者的消息之外,動態綁定要求具有相同名稱的方法的所有實現具有相同的返回類型和相同的參數類型。(靜態類型的接收器是一個例外,因爲編譯器可以瞭解從類類型的方法實現。)

換句話說:更改現有方法的簽名是不是好的形式(IMO ),但只要您靜態鍵入這些方法的接收者就可以了(在您的情況下,這意味着aCard必須聲明爲AddressCard *)。對於運行時,這沒有問題。

不幸的是,你沒有提到編譯器是否給你一個警告,因爲你傳遞了一個NSString *,它預計的是AddressCard *。我希望它能這樣做。

+0

根本沒有警告。它只是在運行時引發異常。 – cfischer 2010-10-17 18:50:16

+0

我一定會期待一個警告。似乎有點草率... – cfischer 2010-10-17 18:51:22

+0

順便說一句,如果我改變我的isEqual:方法的簽名,所以它匹配NSObject的我會得到一個警告:「衝突類型' - (BOOL)isEqual:(id *)aCard。 ?O :-) – cfischer 2010-10-17 19:42:10

1

我最好的猜測:所有的編譯器看到的是一個方法,期望一個指針被指針參數調用。編譯器沒有問題。