Pergunta

me deparei com um problema estranho hoje. Eu criei uma subclasse de UIView e acrescentou apenas 1 método para o código modelo fornecido pelo Xcode.

@interface FloatView : UIView {

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

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

Então, em minha appDelegate eu tinha um código como este:

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

simples bonita, certo? O que isto deve imprimir? Eu pensei que seria algo como "10.0000", mas não, ele imprime "0,000000".

Eu lutei com isso por horas, tentando descobrir o que eu estava fazendo de errado, e então eu mudei o código no meu appDelegate para

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

Só então, é que ele imprima o "10.0000" esperado. Porque isto é assim? Eu já declarou FloatView como uma subclasse de UIView, eu não deveria ser capaz de atribuir um objeto FloatView para um ponteiro UIView sem problemas?

Mesmo que floatView foi declarado um ponteiro para um UIView, é realmente um floatView e ele deve ser capaz de lidar com a mensagem floatTest? Am I totalmente fora da base aqui?

Foi útil?

Solução

Na verdade, o polimorfismo está funcionando como esperado. Se não funcionou, nada teria sido impresso (no seu exemplo, 0.0000 está sendo impresso). A coisa é, enquanto sua instância realmente responde a mensagem testFloat:10.0f, uma vez que o compilador não pode ver estaticamente a declaração de método (como classe UIView não declarar tal método), ele assume que o seu método leva ... como argumento e retorna id.

Quando CGFloat é passada para um método que espera um número variável de argumentos (...), é promovido a double. Assim, o método de recepção é passado um argumento double e pensa que é um float e ele não é impresso corretamente.

Você pode verificar este comportamento, alterando linha NSLog a:

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

Quando o compilador envia a mensagem para FloatView* em vez de um UIView*, pode encontrar a assinatura exata do método. Ele pode ver que realmente espera CGFloat e não promove o argumento para double. Como resultado, ele funciona corretamente.

Além disso, se UIView* continha a declaração de método que levou um CGFloat, o compilador iria chamar o método de forma adequada. Para resumir, este não é um problema polimorfismo; é um problema de assinatura do método faltando.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top