我花了很多时间调试这个,我很想知道到底发生了什么!
在一个非常设计的例子中,假设我们有两个对象,Object1有这个方法:
- (void) testMethod:(NSString *)testString
对象2有这个方法:
- (void) testMethod:(NSArray *)testArray
然后,回到Object1,方法中有以下代码:
NSArray *myArray = [[NSArray alloc] init];
[[[Object2 alloc] init] testMethod:myArray];
编译时,Xcode会发出警告:
不兼容的指针类型将'NSArray *'发送到'NSString *'类型的参数
我相信我说警告是正确的,因为我从未真正指定过类型 Object2。将对象显式地转换为Object2可以修复它,但我的问题是:
#import "Object2.h"
移动到Object1.h而不是Object1.m,为什么警告会消失?谢谢!
答案 0 :(得分:6)
当有两个方法具有相同的选择器但签名不同时,编译器必须决定在编译时使用哪个签名 - 因为签名可能会影响生成的代码。不幸的是,编译器是非常愚蠢的,并且它必须通过检查接收器的静态类型来判断使用哪个签名。在这种情况下,alloc
和init
都返回id
,因此编译器没有任何信息可以决定您发送的是哪种对象这条消息给。所以它基本上是为了打破平局:它闭上眼睛,绕圈旋转了很多次,无论它停止时指向哪个签名,那就是它使用的那个。然后它会根据此随机签名检查您的参数类型,如果猜错了,则认为您传递了错误的类型。
最好的解决方案是避免签名冲突 - 描述性方法名称通常会自行处理,并且为一个或两个选择器添加更多特异性通常是解决您遇到的问题的好方法(例如, testMethodWithName:(NSString *)name
)。
尽可能静态地输入内容也是个好主意。通常这不是问题,因为您无论如何都想要将新创建的对象分配给变量。在紧要关头,如果将方法的结果分配给变量只是笨拙,您也可以将模糊部分转换为正确的类型,例如[(Object2 *)[[Object2 alloc] init] testMethod:myArray]
。