根据到目前为止的经验,您可以在Objective-C中将任何消息发送到任何对象。如果对象确实实现了正确的方法,它将被执行,否则将不会发生任何事情。这是因为在发送消息之前,Objective-C将执行 responsesToSelector 。
我希望到目前为止我是对的。
我做了一个小程序,用于测试每次移动滑块时在何处调用 Action 。同样为了测试,我将发送者设置为NSButton,但实际上它是一个NSSlider。现在我问对象是否会响应 setAlternateTitle 。虽然NSButton可以,而NSSlider则不可以。如果我运行代码并亲自执行responsToSelector ,它将告诉我对象将不响应该选择器。如果我测试其他类似 intValue 的东西,它将响应。所以到目前为止我的代码还不错。
- (IBAction)sliderDidMove:(id)sender
{
NSButton *slider = sender;
BOOL responds =
[slider respondsToSelector:@selector(setAlternateTitle)];
if(responds == YES)
{
NSLog(@"YES");
}
else
{
NSLog(@"NO");
}
[slider setAlternateTitle:@"Hello World"];
}
但是,当我实际发送setAlternateTitle消息时,程序将崩溃,并且我不确定原因。它不应该在发送消息之前做一个responsToSelector吗?
最佳答案
首先,如mvds所说,方法的名称(其选择器)包括所有子部分和冒号字符。
第二,运行时不调用-respondsToSelector:
方法,它通常由用户调用(您自己或想要知道委托(delegate)是否响应协议(protocol)的可选方法的API)。
当您向对象发送消息时,运行时将在对象的类中(通过对象的isa指针)寻找方法的实现。尽管未分派(dispatch)消息本身,但这等效于发送-respondsToSelector:
。如果在类或其父类(super class)中找到该方法的实现,则会使用您传入的所有参数来调用该方法。
如果不是,则运行时为消息提供第二次执行机会。首先将消息+ (BOOL)resolveInstanceMethod:(SEL)name
发送到对象的类:此方法允许您在运行时将方法添加到该类:如果此消息返回YES,则表示它可以重新分派(dispatch)消息。
如果不是,它将给消息第三次执行的机会,它使用选择器发送- (id)forwardingTargetForSelector:(SEL)aSelector
,此方法可以返回另一个对象,该对象可以代表实际接收者响应选择器;如果返回的对象可以响应,则返回将执行方法,并返回值,就像它是原始消息返回的一样。 (注意:此功能从OS X 10.6或iOS 4开始可用。)
如果返回的对象为nil或self(以避免无限循环),则运行时将为消息提供执行该方法的第四次机会……它发送消息- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
以获得方法签名以构建调用。如果提供了一个,则通过消息- (void)forwardInvocation:(NSInvocation *)anInvocation
发送调用。在这种方法中,您可以解析调用并构建其他消息,以所需的任何方式发送给其他目标,然后可以设置调用的返回值……该值将充当原始消息的返回值。
最后,如果对象未返回任何方法签名,则运行时将消息- (void)doesNotRecognizeSelector:(SEL)aSelector
发送到您的对象,NSObject类中此方法的实现将引发异常。
关于objective-c - Objective-C响应到选择器,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4574465/