Вопрос

Сегодня я столкнулся со странной проблемой. Я создал подкласс UIView и добавил только 1 метод в код шаблона, предоставляемый xcode.

@interface FloatView : UIView {

}
- (void)floatTest:(CGFloat)x;
@end

- (void)floatTest:(CGFloat)x {
  NSLog(@"float was %f", x);
}

Тогда в моем appDelegate у меня был такой код:

UIView *floatView = [[FloatView alloc] init];
[floatView floatTest:10.0f];

Довольно просто, верно? Что это должно распечатать? Я думал, что это будет что-то вроде "10,0000", но нет, он печатает "0,000000".

Я боролся с этим часами, пытаясь понять, что я делаю неправильно, а затем я изменил код в appDelegate на

FloatView *floatView = [[FloatView alloc] init];
[floatView floatTest:10.0f];

Только после этого он распечатал ожидаемое "10,0000". Почему это так? Я объявил FloatView как подкласс UIView, разве я не смогу без проблем назначить объект FloatView указателю UIView?

Несмотря на то, что floatView был объявлен указателем на UIView, это действительно floatView, и он должен быть в состоянии обрабатывать сообщение floatTest? Я полностью не в курсе?

Это было полезно?

Решение

На самом деле полиморфизм работает так, как ожидалось. Если бы это не сработало, ничего бы не было напечатано (в вашем примере печатается 0,0000). Дело в том, что ваш экземпляр фактически отвечает на сообщение testFloat: 10.0f , поскольку компилятор не может статически видеть объявление метода (поскольку класс UIView не объявляет такого метод), он предполагает, что ваш метод принимает в качестве аргумента ... и возвращает id .

Когда CGFloat передается методу, который ожидает переменное число аргументов ( ... ), он повышается до double . Таким образом, получающему методу передается аргумент double , и он считает, что это float , и печатается неправильно.

Вы можете проверить это поведение, изменив строку NSLog на:

NSLog(@"%f", *(double*)&x);

Когда компилятор отправляет сообщение FloatView * , а не UIView * , он может найти точную сигнатуру метода. Он может видеть, что действительно ожидает CGFloat и не продвигает аргумент для double . В результате все работает правильно.

Кроме того, если UIView * содержит объявление метода, которое принимает CGFloat , компилятор будет вызывать метод соответствующим образом. Подводя итог, это не проблема полиморфизма; это проблема с отсутствующей подписью метода.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top