2

最新版本的 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];
}

我的问题:由于 myl_topItemOnStack是 typeid并且我没有将其转换为 a NSNumber,我怎么能使用[l_topItemOnStack doubleValue].

我猜我必须先将它转换为 NSNumber 才能访问 NSNumber 方法......

我在这里想念什么?

4

5 回答 5

7

因为 Objective-C 是一种动态语言,消息名称和它们的声明只是编译器的提示——实际的消息查找和发送发生在运行时。因此,即使编译器不知道您的对象响应了doubleValue消息,它仍然能够让您调用

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

和往常一样。

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

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

于 2012-08-29T08:33:40.970 回答
3

id代表任何 Objective-C 类。它与 不同NSObject *,因为在这种情况下,如果不将其转换为第一个,您将无法使用该-doubleValue方法NSNumber

id您可以向( nilis of type )发送任何消息id,而无需将其强制转换为特定类。但是,您应该小心,因为无法识别的选择器会导致崩溃。

编辑:
id意思是:一个指向未知类的Objective-C对象的指针

如果您想了解更多关于 之间的区别id,您应该阅读这篇博文: http: //unixjunkie.blogspot.de/2008/03/id-vs-nsobject-vs-id.htmlvoid *NSObject *

于 2012-08-29T08:32:20.880 回答
3

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

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

return [(NSNumber*)l_topItemOnStack doubleValue];

或将其分配给一个新变量:

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

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

在 MRC 中,编译器实际上可以“假定”参数和返回类型(默认为id)——但这在 ARC 中是被禁止的。

于 2012-08-29T08:33:31.630 回答
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指示接收者是给定类的实例还是从该类继承的任何类的实例

于 2012-08-29T08:35:01.303 回答
1

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

您可以向任何对象发送任何消息;如果编译器找不到编译时类型信息来决定对象是否响应选择器(在这种情况下),编译器会抱怨(警告)doubleValue,但我相信类型的对象id,是通用的,不受此规则的约束,任何事情都会发生在编译时(请更有知识的人确认这一点)。

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

于 2012-08-29T08:35:22.317 回答