搞不清这个动态打字的东西



我正在为面试Cocoa开发人员的人整理一份面试问题清单。我是一名程序员,但我从未用过Objective-C。我偶然发现了一个涉及动态类型的有趣问题。它应该是基本的,我已经尝试并编译了它,但我仍然不确定它是如何以及为什么工作的。

问题是

当您执行以下操作时,在编译时和运行时会发生什么:

NSString *s = [NSNumber numberWithInt:3];
int i = [s intValue];

在调试器中我得到

<>之前I = (int) 3s = (__NSFCNumber*) 0x383(无效地址)之前

NSLog(@"%d",i)的输出为3, NSLog(@"%@",s)的输出为3

谁能给我一个解释,所有这一切是如何处理的编译器和运行时系统也试着记住,我是完全陌生的Objective-C和Cocoa,但不是新的计算机科学?

你的s只是一个标准的C指针,它被分配了一个NSNumber对象(指向a的指针)。

NSNumberNSStringintValue有响应。

s是一个指针,你已经声明将指向一个NSString对象。它可以指向任何东西,但理想情况下它应该指向一个NSString。然而,代码示例让s指向一个NSNumber对象。

只要你只向s发送NSNumber响应的方法,一切都很好(除了编译器警告)。如果你试图发送一个NSString方法给那个对象由s指向NSNumber没有响应你会得到一个异常。如果对象有一个匹配的选择器签名(即:@selector(intValue)),该方法将被调用。

变量"s"的NSString声明仅仅是为了帮助编译器解释变量"s"的意图。它允许编译器在您打算使用某种类型的变量但意外地分配了不同类型的变量的情况下强制执行静态类型检查。在ObjC中,变量可以指向任何对象,而括号语法是向对象发送"消息"的一种方式。发送消息指示编译器生成查找实现该消息的函数的代码。在objective中,消息也被称为选择器。(低级别的细节稍微复杂一些,但在高层次上,这就是它的工作原理。)这就是动态类型的动态部分,也被称为"duck typing"。这个想法是,如果它看起来像一只鸭子,你应该能让它像鸭子一样嘎嘎叫。从本质上讲,任何遵循一定形状的对象都可以赋值给适合该形状的类型。

考虑以下内容:

Dog *myPuppy = [[Cat alloc] init] autorelease];
[myPuppy walk];
Food *preparedDish = [self prepareMealForPet];
[myPuppy eat: preparedDish];

编译器会在这里标记你,表明你打算花时间和一只狗在一起,但实际上是在和一只猫打交道。然而,这是完全正确的,因为猫的形状和狗很像,它们都能走路,也能吃现成的食物。Duck typing可以让您避开这一点,因为在许多情况下,您需要接受事先不知道的变量类型。此外,通过自省,您可以在运行时发现对象的形状。考虑上面的代码,如果我们想让我们的小狗吠叫。我们会得到一个异常,应用会崩溃。然而,我们可以使用自省来询问我们的对象是否响应"bark"消息,以避免崩溃。

if([myPuppy respondsToSelector:@selector(bark)]) {
   [myPuppy bark];
}

最新更新