覆盖方法时严格与松散类型

时间:2010-10-17 16:15:39

标签: objective-c cocoa override strong-typing loose-typing

我在“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的方法时引发异常:

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

发生了什么事?在地球上如何将NSString传递给期望其他东西的方法?在覆盖它时更改方法的签名是否正确?

2 个答案:

答案 0 :(得分:1)

我最好的猜测:所有编译器看到的是一个期望用指针参数调用指针的方法。编译器没问题。

答案 1 :(得分:1)

运行时通过选择器区分消息。具有相同名称的所有方法都具有相同的选择器。方法参数对选择器没有影响。在您的情况下,选择器为isEqual:

这是来自Apple的“Objective-C编程语言”(强调我的):

  

消息传递例程只能通过选择器访问方法实现,因此它会使用相同的选择器来处理所有方法。它从选择器中发现方法的返回类型及其参数的数据类型。 因此,除了发送到静态类型接收器的消息之外,动态绑定要求具有相同命名方法的所有实现具有相同的返回类型和相同的参数类型。(静态类型接收器是此规则的一个例外,因为编译器可以从类类型中了解方法实现。)

换句话说:更改现有方法的签名不是好形式(IMO),但只要您静态键入这些方法的接收者(在您的情况下,这意味着必须声明aCard,它就没问题了)作为AddressCard *)。对于运行时,这没问题。

不幸的是,你没有提到编译器是否给你一个警告,因为你传递的NSString *期望AddressCard *。我希望它能这样做。