2

在一些示例代码中,将 anNSNumber添加到可变数组中:

// In the .h, as an instance variable:
NSMutableArray *sequence;

// In the .m file:
sequence = [[NSMutableArray alloc] initWithCapacity:100];

[sequence addObject:[NSNumber numberWithInt:123]];

然后稍后,当需要整数时,它使用:

[(NSNumber *)[sequence objectAtIndex:aCounter] intValue]

我只是想知道为什么(NSNumber *)需要演员表?因为没有它,程序也可以正常运行。这只是一个好习惯吗?如果是这样,它可以防止发生什么?如果有一个错误使得一个元素不是NSNumber *,那么强制转换它也会产生奇怪的行为。

4

5 回答 5

1

强制转换只会使编译器相信该对象(它以 type 的形式返回id,即没有其他信息的通用对象类型!)实际上是一个NSNumber,因此它可以识别其intValue等方法的正确性。它不会在运行时使事情有所不同。如果对象不是 NSNumber,那么无论是否进行强制转换,它都会在运行时崩溃。

于 2012-04-30T06:49:14.053 回答
1

没有强制转换就可以了,强制转换只是明确表明您将其视为 NSNumber,如果您有错误并且这不是NSNumber(或更准确地说,不响应intValue),您会得到一些无论如何,奇怪的行为。

于 2012-04-30T06:49:36.943 回答
1

我只是想知道为什么需要演员表(NSNumber *)?

如果在运行时实际调用的选择器的签名对翻译可见,并且所有对翻译可见的选择器签名与被调用的选择器匹配,则不需要它。

您可能在想“什么?这很复杂!这也容易出错,尤其是随着我的程序不断发展!”

如果同一选择器的多个选择器签名可见并且您发送消息id,那么您应该期待未定义的行为,因为未键入 objc 集合并且编译器可能与正确的选择器不匹配(如果您的警告级别很高并且您的包含都是正确的,您可以看到有关此的警告)。

避免这种情况的简单方法是通过赋值重新引入正确的类型:

NSNumber * n = [array objectAtIndex:i];
int a = [n intValue];

或通过铸造:

int a = [(NSNumber*)[array objectAtIndex:i] intValue];

因此编译器可以根据类型适当地匹配选择器,并在对象可能不响应给定选择器、参数或返回类型不匹配、或者您将其转换为的类型的接口是在翻译中不可见——毕竟,您应该对集合包含的内容有所了解。

适当地引入类型安全是一种非常好的做法。

于 2012-04-30T07:31:57.093 回答
1

//在Objective-C中,任何对象都可以向任何其他对象发送消息。//所以这里两个statmenst都是完全有效的,但是

[(NSNumber *)[sequence objectAtIndex:aCounter] removeFromSuperview]; //这会引发警告并让你知道 removeFromSuperview 不会被调用

[[sequence objectAtIndex:aCounter] removeFromSuperview];//这里你不会得到任何警告

于 2012-04-30T06:58:06.107 回答
0

只需要强制转换来阻止编译器抱怨它不确定你知道你在做什么。

编译器在编译时为您做的一件事是检查消息接收者的接口是否表示他们响应您发送的消息(intValue在这种情况下)。的接口NSNumber确实说它响应intValue,但返回类型objectAtIndex:id,它是一个通用指针。编译器无法知道该指针另一端的对象类型是什么——直到运行时才知道。

强制转换告诉编译器您确实知道类型并且它不需要警告您(或者,在某些情况下,在 ARC 下,给出错误)关于它不确定消息的接收者是否响应的事实。

请注意,如果您将强制转换的类更改为不响应的内容intValue(例如NSDate),编译器会抱怨您,如果对象确实仍然是NSNumber,则消息在运行时仍然会成功。铸造不能改变对象的类型;它只是编译器的注释。*


*在某些情况下,它还可以增加代码的可读性。

于 2012-04-30T06:51:19.450 回答