Objective c 为什么@selector可以调用在实现文件中声明的方法?

Objective c 为什么@selector可以调用在实现文件中声明的方法?,objective-c,cocoa,nsnotificationcenter,Objective C,Cocoa,Nsnotificationcenter,我在类a的.m文件中声明(在@interface和@end之间)并实现了一个方法。例如: - (void)zoneChange:(NSNotification *)note { NSLog(@"The system time zone has changed!"); } 在B类中,我想在系统区域更改时向观察者发送zoneChange消息 [[NSNotificationCenter defaultCenter] addObserver:anObserver

我在类a的.m文件中声明(在@interface和@end之间)并实现了一个方法。例如:

- (void)zoneChange:(NSNotification *)note
{
    NSLog(@"The system time zone has changed!");
}
在B类中,我想在系统区域更改时向观察者发送
zoneChange
消息

[[NSNotificationCenter defaultCenter] addObserver:anObserver
                                         selector:@selector(zoneChange:)
                                             name:NSSystemTimeZoneDidChangeNotification
                                           object:nil];

上面的代码有效。当用户更改Mac上的时区时,将调用
zoneChange
方法。但是,编译器对@selector:未声明的选择器“zoneChange:发出警告。让我困惑的是,既然
zoneChange
是一个私有方法,为什么它可以被类B中的@selector在类a之外看到?有人能给我解释一下吗?

私有方法就是:私有的。他们仍然存在,只是对外界保密。Objective-C中没有内置任何东西来检查从何处调用方法并在运行时进行投诉;关于未声明选择器的编译时警告正是类B无法看到您期望的方法

在Objective-C的世界中,当您编写
[receiver zoneChange:note]
时,实际上是在向接收对象
接收器
发送消息(
zoneChanged:
),而不是直接进行函数调用。虽然最终会有一些C函数被调用,但Objective-C消息仍然与传统的C函数有很大的不同——我认为这就是为什么您感到困惑的原因


C函数是“静态的”。调用C函数的过程实际上只是跳到某个点并执行某些代码,这是在编译时确定的。但是,消息是在运行时处理的。Objective-C是一种动态语言,这意味着您可以在运行时添加方法甚至类。因此,无法确定类是否在编译时实现(或响应)一个特定的选择器。例如,
NSManagedObject
的一些访问器在调用时在运行时添加。因此,尽管有警告,实际上您可以使用
performSelector
将任何消息发送到任何对象(包括
nil
),而不会出现编译错误。

这是否意味着如果编译器不抱怨,外部世界可以调用私有方法?@WangYudong:没错。您甚至可以通过在使用
@selector
之前在类扩展中声明方法来绕过当前警告。