2011-08-25 25 views
2

任何解决此问题的方法?将NSNumber *传递给NSString *期望参数不会导致编译器警告/错误

我改变了我的一个函数的签名来传递NSString对象,而不是NSNumber对象。除了我有一些仍然通过旧的NSNumber对象的实例。很难追查,因为编译器不会显示任何错误或警告。我试图删除DerivedData文件夹。没有帮助。

我也试过做分析,也没有发现那些问题。

我知道我可以做一个NSAssert检查,以确保传入的参数类型是正确的,但这似乎是倒退。这应该是编译器拿起并警告我的东西。

有什么建议吗?

- (void) test:(NSString *)par;

调用

NSString *str = (NSString *)[array objectAtIndex:0];

除非对象是NSNumber的,所以在技术上它转换一个NSNumber到的NSString。调试器将其视为NSNumber,所以不知道为什么它首先被允许。

+1

你可以做的事情不多,除非学习在需要的地方更防守地编码。当你明确表演时,你必须确保它能奏效。 –

+0

是否没有可以设置调试这些不良类型的断点? – David

+1

@David - 如果你明确地指定了一个像这样的指针,那么它就是游戏结束了。编译器如何告诉你没有*意味着*要做到这一点?它不知道阵列中的内容 - 您必须自己维护这些信息。 –

回答

2

有什么办法解决这个问题?

不容易。断言(如你所说)是一个起点。

我改变了我的函数的签名传递NSString对象,而不是NSNumber对象。

objc不能这样工作--objc对象只是通过它们的参数/变量在执行时传递地址。

当类型转换时没有由语言提供的显式类型转换;如果这是你的期望。

objc也不使用类型安全转换来确定参数是否是它正在转换的类型。

除了我有一些仍然通过旧的NSNumber对象的实例。很难追查,因为编译器不会显示任何错误或警告。我试图删除DerivedData文件夹。没有帮助。

你得到NSNumbers,因为这是数组中存在的。

我也试过做分析,也没有发现那些问题。

这是一个非常动态的语言,这就是它的设计。

分析仪无法检测到这些问题或寻找它们,因为检查必须在运行时执行。

此外,传递objc对象并动态使用它们(使用respondsToSelector:isKindOfClass:)常见。

我知道我可以做一个NSAssert检查,以确保传入的参数类型是正确的,但这似乎是倒退。这应该是编译器拿起并警告我的东西。

我使用断言,并写了几个检查和类型来返回类型安全,我想要它。

我知道没有这个公共库 - 你可能是自己实施你想要的检查。为这些检查创建一个简单的标题并实施它们非常简单。

除了对象是NSNumber,在技术上它将NSNumber强制转换为NSString。调试器将其视为NSNumber,所以不知道为什么它首先被允许。

对于objc变量,调试器评估地址处的对象以确定其类型,而不是使用变量声明的类型。

1

调试器将其视为正确(NSNumber)类型的事实并不意味着编译器也应该看到这一点。编译在调试之前发生,编译器唯一的信息是静态源代码。如果你将一个指针转换为另一种类型,那么你就会有效地告诉编译器“忘记你对这个指针的所有知识;现在就是这个类型”。编译器无法知道在运行时实际上会有不同的类型。

编译器会警告你有关冲突的参数类型,但为了看到该警告,类型在编译时必须实际发生冲突。铸造强制类型在编译时匹配,所以您唯一的选择是更改或删除所有违规的强制转换。

0

为了进一步讨论:Objective-C对象可以被视为无类型。由于运行时完全反射,因此[objTypeA someSelector][objTypeB someSelector]都会生成完全相同的编译代码。这与C++等语言形成鲜明对比,其中需要了解对象的类型才能清楚地知道如何调用特定的方法。

描述这个的另一种方式是Objective-C支持duck typing。所以你的问题的解决方案是:

@interface NSString (stringValue) 

- (NSString *)stringValue { return self; } 

@end 

// ... elsewhere ... 

- (void)test:(id)par 
{ 
    NSString *stringValueOfPar = [par stringValue]; 

    // now proceed with stringValueOfPar as you previously did with par 
} 

你所做的事有加宽您的测试方法的定义,这样,而不是采取一种特定类型的,它需要的任何类型的将自己转换为字符串当你调用stringValue时。 NSNumber已经满足该条件,但NSString没有。所以你扩展NSString。所以你创建的是一个非正式的协议。

贾斯廷的答案是更实际和正确的使用,这一个是有效地部署Objective-C的能力来修补你不应该在第一个地方犯的错误。我已经发布了这个答案,试图帮助解释为什么这种事情不仅仅在Objective-C中允许,但有时非常有用。

相关问题