在一些示例代码中,NSNumber
被添加到可变数组中:
// 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 *
,那么转换它也会产生奇怪的行为。
答案 0 :(得分:1)
仅使用Casting使编译器相信该对象(从id
类型返回,即没有其他信息的通用对象类型!)实际上是NSNumber
,因此它可以识别对象它的intValue
等方法。它不会在运行时使事情有所不同。如果对象不是NSNumber,那么它将在运行时崩溃,无论是否有转换。
答案 1 :(得分:1)
在没有强制转换的情况下这样做是很好的,如果你有一个bug并且这不是NSNumber
(或更准确地说,不要),那么强制显示你将它视为NSNumber回复intValue
)你会得到一些奇怪的行为。
答案 2 :(得分:1)
//在objective-C中,任何对象都可以向任何其他对象发送消息。 //所以这里两个statmenst完全有效,但是
[(NSNumber *)[sequence objectAtIndex:aCounter] removeFromSuperview]; //这会抛出警告,让你知道removeFromSuperview shpuld'nt被称为
[[sequence objectAtIndex:aCounter] removeFromSuperview]; //这里你不会得到任何警告
答案 3 :(得分:1)
我只是想知道为什么需要演员表(NSNumber *)?
如果在运行时实际调用的选择器的签名对于翻译是可见的,并且翻译可见的所有选择器签名与称为的选择器匹配,则不需要。
你可能在想“什么?这很复杂!这也很容易出错,特别是当我的程序发展时!”
如果同一选择器的多个选择器签名可见并且您发送消息id
,那么您应该期望未定义的行为,因为objc集合未键入且编译器可能与正确的选择器不匹配(如果您的警告级别为高,你的包括都是正确的,你可以看到关于这个的警告。)
避免这种情况的简单方法是通过赋值重新引入正确的类型:
NSNumber * n = [array objectAtIndex:i];
int a = [n intValue];
或通过施法:
int a = [(NSNumber*)[array objectAtIndex:i] intValue];
因此编译器可以为类型匹配选择器,并在对象可能不响应给定选择器时,或者参数或返回类型不匹配时,或者如果您输入的类型的接口时警告您它在翻译中是不可见的 - 毕竟,你应该知道集合包含什么。
正确引入类型安全是一种非常好的做法。
答案 4 :(得分:0)
只需要演员来阻止编译器抱怨它不确定你知道自己在做什么。
编译器在编译时为您做的一件事是检查消息接收者的接口是否表示他们响应您正在发送的消息(在这种情况下为intValue
)。 NSNumber
的接口确实表示它响应intValue
,但objectAtIndex:
的返回类型是id
,这是一个通用指针。编译器无法知道该指针另一端的对象类型是什么 - 直到运行时才会知道。
演员告诉编译器你确实知道这个类型,并且它不需要警告你(或者,在某些情况下,在ARC下,给出一个错误)关于它不确定是否接收器的事实消息响应。
请注意,如果您将转换的类更改为不响应intValue
的内容(例如NSDate
),则编译器会抱怨您,但如果对象确实仍然是NSNumber
,则消息仍将在运行时成功。铸造不能改变对象的类型;它只是编译器的注释。*
*在某些情况下,它也可以提高代码的可读性。