1

我正在阅读 iOS Big Nerd Ranch 书,其中一个示例显示了如何将观察者添加到 NSNotificaionCenter :

    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(orientationChanged:)
                                             name:UIDeviceOrientationDidChangeNotification
                                           object:[UIDevice currentDevice]];

现在在orientationChanged中,方向是从NSNotification中发布的对象中检索的:

- (void)orientationChanged:(NSNotification *)note {
    NSLog(@"orientationChanged  %d", [[note object] orientation]);
 }

我的困惑在于这一行:[[note object]orientation]

NSNotification 的对象返回和id,所以这意味着我们在编译时不知道对象的类型是 UIDevice 。但是,我们可以从返回的对象中访问方向,而不会从编译器中出错。编译器如何知道对象类型是 UIDevice 并且访问方向是可以接受的?

4

2 回答 2

4

编译器如何知道对象类型是UIDevice什么?

它没有。

它看到它是id. 该类型id是通用对象类型。因此,如果您向它发送任何消息,编译器就会毫无错误地接受。即使你发送一个不存在的。

这是因为 Objective-C 是一种动态语言。方法调用(消息发送)、绑定,甚至类型都是在运行时由 Objective-C 运行时库推断的。如果您向对象发送它未实现的消息(“响应”),则将引发运行时异常,而不是编译器错误。

顺便说一句,id假定消息 to 返回id(因此最多可以安全地返回指针大小的值,例如大多数整数),或者编译器查看所有类上的所有可用选择器名称并尝试将类型匹配到它找到的选择器之一,以防它确实被发现。

于 2013-03-20T15:58:21.633 回答
2

Objective-C 中的消息在运行时动态绑定到方法实现,而不是编译时。如果您尝试向未实现方法的对象发送消息,那么它将抛出发送到实例异常的无法识别的选择器。

您可以通过向对象发送消息“respondsToSelector:”来询问对象是否响应选择器来防止引发此异常。如果此方法返回 YES,那么您可以安全地向它发送消息。这在类中实现委托时很常见,因为协议中的某些方法可能是可选的。

有关 Objective-C 消息传递如何工作的更多信息,您可以阅读 Apple Objective-C 运行时编程指南:https ://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtHowMessagingWorks.html #//apple_ref/doc/uid/TP40008048-CH104-SW1

于 2013-03-20T16:03:37.020 回答