无法弄清楚这个动态类型的事情

发布于 2024-12-08 04:20:15 字数 635 浏览 6 评论 0原文

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

问题是

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

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

在调试器中,我得到

i = (int) 3
s = (__NSFCNumber*) 0x383 (invalid address)

The output of NSLog(@"%d",i) is 3,并且NSLog(@"%@",s) 的输出是 3

有人可以给我解释一下编译器和运行时系统如何处理所有这些,同时记住我对 Objective-C 和 Cocoa 完全陌生,但对计算机科学一点也不陌生?

I'm putting together a list of interview questions for someone interviewing to be a Cocoa developer. I'm a programmer, but I've never done Objective-C. I stumbled upon an interesting question that involves dynamic typing. It should be elementary, I've tried it and compiled it, but I'm still not sure how and why it works.

The question is

What happens at compile time and runtime when you do the following:

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

In the debugger I get

i = (int) 3
s = (__NSFCNumber*) 0x383 (invalid address)

The output of NSLog(@"%d",i) is 3, and the output of NSLog(@"%@",s) is 3.

Can someone give me an explanation of how all of this is handled by the compiler and the runtime system by also trying to keep in mind that I'm completely new to Objective-C and Cocoa, but not at all new to computer science?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦里人 2024-12-15 04:20:15

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

NSNumber 以及 NSString 响应 intValue。就是这样。

Your s is just a standard C pointer, to which an NSNumber object (pointer to a) is assigned.

NSNumber, as well as NSString, responds to intValue. That's about it.

不回头走下去 2024-12-15 04:20:15

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

只要您只向 s 发送方法,这些方法是 NSNumber 响应的方法,一切都很好(编译器警告除外)。如果您尝试将 NSString 方法发送到 s 所指向的对象,而 NSNumber 没有响应,您将收到异常。如果对象具有匹配的选择器签名(即:@selector(intValue)),则将调用该方法。

s is a pointer which you've declared will point to an NSString object. It can point to anything, but ideally it should point to an NSString. The code sample, however, has s pointing to an NSNumber object.

As long as you only send methods to s that are methods that NSNumber responds to everything is fine (except maybe for compiler warnings). If you were to try to send an NSString method to that object pointed to by s that NSNumber doesn't respond to you would get an exception. If the object has a matching selector signature (ie: @selector(intValue)) the method will be called.

恍梦境° 2024-12-15 04:20:15

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

请考虑以下情况:

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

编译器会在此处标记您,表明您打算花时间与狗在一起,但实际上正在与猫打交道。然而,这是完全正确的,因为猫的形状与狗相似,它们都可以行走和吃准备好的食物。鸭式类型可以让您摆脱这种情况,因为在很多情况下您需要接受事先未知的变量类型。此外,通过内省,您可以在运行时发现对象的形状。在上面的代码中考虑一下我们是否想让我们的小狗吠叫。我们会遇到异常,应用程序会崩溃。然而,我们可以使用内省来询问我们的对象是否响应“吠叫”消息以避免崩溃。

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

The declaration of NSString for variable "s" is done merely to assist the compiler in interpreting your intention of variable "s". It allows the compiler to enforce static type checking in the case where you intended to use a variable of a certain type but accidentally assigned a variable of a different type. In ObjC a variable can point to any object while the bracket syntax is a means of sending a "message" to the object. Sending a message instructs the compiler to generate code that looks up the function that implements the message. Also in ObjectiveC messages are referred to as selectors. (The low level details are slightly more involved but at a high level that's how it works.) That's the dynamic part of dynamic typic, which is also referred to as "duck typing". The idea is if it looks like a duck you should be able to make it quack like a duck. In essence any object that follows a certain shape can be assigned to a type that fits the shape.

Consider the following:

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

The compiler would flag you here indicating you intended to spend time with a Dog but are actually dealing with a cat. However it is perfectly valid since a cat is shaped similar to a dog in that they both can walk and eat prepared meals. Duck typing lets you get away with this since there are many cases where you would need to accept types of variables that are not known in advance. Furthermore through introspection you can discover the shape of your object at runtime. Consider in the above code if we wanted to ask our puppy to bark. We would get an exception and the app would crash. However we could use introspection to ask if our object responds to the "bark" message to avoid a crash.

if([myPuppy respondsToSelector:@selector(bark)]) {
   [myPuppy bark];
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文