Строгая и свободная типизация при переопределении метода - PullRequest
2 голосов
/ 17 октября 2010

У меня есть класс AddressCard из примера в «Программирование в Objective C», и я реализую метод isEqual:

Сигнатура этого метода в NSObject использует свободную типизацию для параметра:

- (BOOL)isEqual:(id)anObject

OTOH, пример кода в книге использует строгую типизацию:

- (BOOL) isEqual:(AddressCard *) aCard

Я не уверен, что полностью понимаю, что делает компилятор в этом случае.Я попытался сравнить AddressCard с NSString ([aCard isEqual: @"Foo"]), ожидая либо ошибки во время выполнения (если система использует мой метод), либо что система вызовет версию IsEqual из NSObject.

Вместо этого был вызван мой метод (хотя этот параметр был 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 ]

1 голос
/ 17 октября 2010

Среда выполнения различает сообщения по их селектору. Все методы с одинаковым именем имеют одинаковый селектор. Аргументы метода не влияют на селектор. В вашем случае селектором является isEqual:.

Это от Apple "The Objective-C Programming Language" (выделено мной):

Подпрограмма обмена сообщениями имеет доступ к реализациям методов только через селекторы, поэтому она обрабатывает все методы одним и тем же селектором. Он обнаруживает тип возвращаемого значения метода и типы данных его аргументов из селектора. Следовательно, за исключением сообщений, отправляемых статически типизированным получателям, динамическое связывание требует, чтобы все реализации методов с одинаковыми именами имели одинаковый тип возвращаемого значения и одинаковые типы аргументов. (Получатели статического типа являются исключением из этого правила, поскольку компилятор может узнать о реализации метода из типа класса.)

Другими словами: изменение сигнатуры существующего метода не является хорошей формой (IMO), но это нормально, если вы статически вводите получатели этих методов (в вашем случае это означает, что aCard должен быть объявлен как AddressCard *). Для среды выполнения это не проблема.

К сожалению, вы не упоминаете, дает ли компилятор предупреждение, потому что вы передаете NSString * там, где он ожидает AddressCard *. Я ожидаю, что это так.

1 голос
/ 17 октября 2010

Мое лучшее предположение: все, что видит компилятор, - это метод, который ожидает, что указатель вызывается с параметром указателя.Нет проблем для компилятора.

...