为什么objective-c在差异类中不支持相同的方法名?

时间:2014-06-22 08:10:55

标签: objective-c

以下是 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对象的类结构。哪个应该在idClassWithInt类型之间没有区别。

为什么objective-c编译器无法识别正确的方法?

注意:我问这个问题,因为具有相同的方法名称,但不同类的不同参数类型对我来说是合理的。但似乎不可能因为编译器限制或语言设计(不支持方法重载等)。

2 个答案:

答案 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

有两种方法可以调用它。如果没有帮助,编译器无法弄明白。因此错误信息。