将NSNumber *传递给NSString * expected-parameter不会导致编译器警告/错误

时间:2011-08-25 16:33:56

标签: objective-c debugging xcode4

有什么方法可以解决这个问题?

我更改了函数的签名以传递NSString对象而不是NSNumber对象。除了我有一些仍然传递旧NSNumber对象的实例。由于编译器没有显示任何错误或警告,因此很难跟踪。我尝试删除DerivedData文件夹。没有帮助。

我也尝试过分析,但也没有发现这些问题。

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

有什么建议吗?

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

调用

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

除了对象是NSNumber之外,所以从技术上讲它会将NSNumber强制转换为NSString。调试器将其视为NSNumber,因此不确定为什么首先允许它。

3 个答案:

答案 0 :(得分:2)

  

有什么方法可以解决这个问题吗?

不容易。断言(正如你所提到的)是一个起点。

  

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

objc不起作用 - objc对象只是在执行时通过参数/变量传递地址。

在进行类型转换时,语言没有提供明确的类型转换;如果这是你的期望。

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

  

除了我有一些仍然传递旧NSNumber对象的实例。由于编译器没有显示任何错误或警告,因此很难跟踪。我尝试删除DerivedData文件夹。没有帮助。

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

  

我也尝试过分析,但也没有发现这些问题。

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

分析器无法接收这些问题或查找它们,因为必须在运行时执行检查。

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

  

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

我使用断言并写了几个检查和类型,以便在我想要的地方返回类型安全。

我知道没有公共资源管理系统 - 您可能需要自己实施所需的检查。为这些检查创建一个简单的标题并实现它们很容易。

  

除了对象是NSNumber之外,所以从技术上讲它会将NSNumber强制转换为NSString。调试器将其视为NSNumber,因此不确定为什么首先允许它。

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

答案 1 :(得分:1)

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

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

答案 2 :(得分:0)

进一步讨论:Objective-C对象可以被视为无类型。因为运行时是完全反射的,所以[objTypeA someSelector][objTypeB someSelector]都会产生完全相同的编译代码。这与C ++之类的语言形成对比,在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。所以你创建的是一个非正式的协议。

Justin的答案是更实用,更合适的一个,这个有效地部署了Objective-C的能力来修补你不应该首先犯的错误。我已经发布了这个答案,试图帮助解释为什么这种事情不仅仅在Objective-C中允许,但有时非常有用。