以下是 Learning objective-c 2.0 的代码段 完整代码:
ClassWithFloat.h
#import <Foundation/Foundation.h>
@interface ClassWithFloat : NSObject
{
float value;
}
-(void)setValue:(float)aValue;
@end
ClassWithFloat.m
#import "ClassWithFloat.h"
@implementation ClassWithFloat
-(void)setValue:(float)aValue
{
value = aValue;
}
@end
ClassWithInt.h
#import <Foundation/Foundation.h>
@interface ClassWithInt : NSObject
{
int value;
}
-(void)setValue:(int)aValue;
@end
ClassWithInt.m
#import "ClassWithInt.h"
@implementation ClassWithInt
-(void)setValue:(int)aValue
{
value = aValue;
}
@end
的main.m:
#import <Foundation/Foundation.h>
#import "ClassWithFloat.h"
#import "ClassWithInt.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
id number = [[ClassWithInt alloc] init];
[number setValue:3];
}
return 0;
}
无法编译,在更改为ClassWithInt* number
之后无效。
错误讯息:
/Users/jcyangzh/src/oc/SameName/SameName/main.m:17:9: Multiple methods named 'setValue:' found with mismatched result, parameter type or attributes
但是,由于objective-c在某种程度上是一种动态编程语言,因此消息调用将被转换为本机C方法调用。
obj_msgSend(number, @selector(setValue:), 3)
obj_msgSend
方法通过number
变量找到isa
对象的类结构。哪个应该在id
或ClassWithInt
类型之间没有区别。
为什么objective-c编译器无法识别正确的方法?
注意:我问这个问题,因为具有相同的方法名称,但不同类的不同参数类型对我来说是合理的。但似乎不可能因为编译器限制或语言设计(不支持方法重载等)。
答案 0 :(得分:3)
问题实际上是你的对象只在词法范围内输入为id。 编译器不知道要使用哪个相同名称/选择器的方法。 您有多个具有该选择器但具有不同签名的类,因为它们的参数是不同的类型。 在这种情况下你应该避免使用id 或者在消息中对您的对象进行类型转换发送括号,以告诉编译器使用哪种类的方法 要么 以if的顺序重复括起相同的消息调用([obj isKindOf: 检查。 (这里很疯狂) 要么 最好从NSNumber类中获取有关良好方法命名约定的提示,并执行类似setFloatValue:和setIntValue的操作:它更易读,更清晰,有助于编译器。
但是只要你拥有和id类型,你需要检查对象是否是KindOf:或者你是在寻找麻烦。
答案 1 :(得分:1)
非常 非常 错误 ,方法具有相同名称但签名不同。 (它在某处记录但我现在找不到)
调用setValue:(float)
之间的调用转换与setValue:(int)
不同,编译器必须生成不同的二进制代码。
正如你所说,最终会出现类似
的内容obj_msgSend(number, @selector(setValue:), 3)
但它们不同
obj_msgSend(number, @selector(setValue:), (int)3)
obj_msgSend(number, @selector(setValue:), (float)3.0f)
编译器必须在编译时决定生成哪个版本。因为int
类型和float
类型的pass参数之间的调用转换不同。
给定代码
ClassWithInt *number = [[ClassWithInt alloc] init];
[number setValue:3];
编译知道需要在类型信息的帮助下使用int
生成版本。
但没有类型信息
id number = [[ClassWithInt alloc] init];
[number setValue:3]; // is this takes int or float? if it is float then 3 need to be convert to float value first
有两种方法可以调用它。如果没有帮助,编译器无法弄明白。因此错误信息。