Objective-C理解isKindOfClass

时间:2012-08-29 08:27:00

标签: objective-c casting nsnumber

最新版本的Objective-C和XCode(4.4)。

我有一个代码段,我无法理解为什么我能够使用某些行,让我解释一下:

// For understanding purpose : (NSMutableArray*)_programStack

id l_topItemOnStack = [_programStack lastObject];
if([l_topItemOnStack isKindOfClass:[NSNumber class]])
{
    return [l_topItemOnStack doubleValue];
}

我的问题:由于我的l_topItemOnStack类型为id,而我没有将其投放到NSNumber,我如何才能使用[l_topItemOnStack doubleValue]。< / p>

我猜我必须首先将其转换为NSNumber来访问NSNumber方法......

我在这里缺少什么?

5 个答案:

答案 0 :(得分:7)

因为Objective-C是一种动态语言,所以消息名称及其声明只是编译器的提示 - 实际的消息查找和发送在运行时发生。因此,即使编译器不知道您的对象响应doubleValue消息,它仍然可以将您的呼叫转换为

return objc_msgSend(l_topItemOnStack, @selector(doubleValue));

通常。

此外,编译器查找在包含的头中任何地方声明的所有选择器,并尝试使用实际上下文找到最佳匹配 - 这里doubleValue是唯一的名称 - 它仅在NSNumber上声明,因此编译器< em>假设您的对象确实是NSNumber。

如果你真的想避免这种情况,可以在调用方法时强制转换对象,或者最初将其声明为NSNumber。

答案 1 :(得分:3)

id代表任何Objective-C类。它与NSObject *不同,因为在这种情况下,如果不首先将-doubleValue投射到NSNumber,您将无法使用id方法。

您可以向nil发送任何消息(id类型为id),而无需将其投射到特定类。不过,你应该小心谨慎,因为一个无法识别的选择器会导致崩溃。

修改
id表示:指向未知类的Objective-C对象的指针

如果您想详细了解void *NSObject *和{{1}}之间的区别,请阅读以下博文:http://unixjunkie.blogspot.de/2008/03/id-vs-nsobject-vs-id.html

答案 2 :(得分:3)

编译器只是将对象与翻译可见的选择器匹配(通过#import)。

如果在查找选择器匹配时存在歧义,或者如果签名不匹配并且声明了多个选择器,则可能会抱怨。在这种情况下,您要么必须转换对象:

return [(NSNumber*)l_topItemOnStack doubleValue];

或将其分配给新变量:

NSNumber * number = l_topItemOnStack;
return [number doubleValue];

为了消除编译器的类型,以便知道正确的选择器的签名(例如,它可以正确设置堆栈)。

在MRC中,编译器实际上可以假设&#39;参数和返回类型(默认为id) - 但在ARC中禁止使用。

答案 3 :(得分:3)

首先,检查 topItemOnStack是否为NSNumber 的类型 NSNumber继承NSValue

NSValue对象是单个C或Objective-C数据项的简单容器。它可以包含任何标量类型,如int,float和char,以及指针,结构和对象ID

topItemOnStack can now be of any type floatValue, intValue or doubleValue as per our requirement

使用isKindOfClass不会将topItemOnStack转换为NSNumber,而是检查它是否为NSNumber类型。

isKindOfClass 表示接收者是给定类的实例还是从该类继承的任何类的实例

答案 4 :(得分:1)

Objective-C对象具有捆绑在(着名的isa指针)中的运行时类型信息。

您可以向任何对象发送任何消息;如果编译器无法找到编译时类型信息来判断对象是否响应选择器(在本例中为doubleValue),编译器会抱怨(警告),但我相信id类型的对象,是通用,免于此规则,任何事情都在编译时进行(有人更有见识,请确认)。

当然,如果id类型的变量指向的对象没有实现相应的方法(即,无法响应发送的消息),则会抛出异常。在iOS中,这意味着应用程序崩溃(除非有问题的对象已覆盖此默认行为)。在OS X上,并不总是(再次,有人更有见识,请确认)。