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

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

这是怎么回事?到底如何将 NSString 传递给期望其他方法的方法?覆盖时更改方法的签名可以吗?

4

2 回答 2

1

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

这是来自 Apple 的“The Objective-C Programming Language”(强调我的):

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

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

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

于 2010-10-17T17:00:11.200 回答
1

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

于 2010-10-17T16:39:41.710 回答