我正在阅读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]);
}
我的困惑在于这一行: [[注意对象]方向]
NSNotification的对象返回, id ,这意味着我们不知道对象的类型是编译时的UIDevice。但是,我们能够从返回的对象访问 orientation ,而不会出现编译器的错误。编译器如何知道对象类型是UIDevice并且可以接受访问方向?
答案 0 :(得分:4)
编译器如何知道对象类型为
UIDevice
?
没有。
它看到它是id
。类型id
是通用对象类型。因此,如果您发送任何消息,编译器会毫无错误地接受。即使你发送了一个不存在的。
这是因为Objective-C是一种动态语言。方法调用(消息发送),绑定,偶数类型在运行时期间由Objective-C运行时库推断。如果您向对象发送一条未实现的消息(“响应”),则抛出运行时异常而不是编译器错误。
顺便说一下,假设id
的消息返回id
(所以大多数指针大小的值,例如大多数整数都可以安全地返回),或者编译器查看所有的所有类上都有可用的选择器名称,并尝试将该类型与它找到的选择器之一匹配,以防它确实找到。
答案 1 :(得分: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