Objective-C响应ToSelector

时间:2011-01-01 15:12:00

标签: objective-c cocoa

根据我迄今所学到的知识:在Objective-C中,您可以向任何对象发送任何消息。如果对象确实实现了正确的方法,那么它将被执行,否则不会发生任何事情。这是因为在发送消息之前,Objective-C将执行 respondsToSelector

我希望到目前为止我是对的。

我做了一个小程序来测试每次移动滑块时调用动作的位置。同样用于测试我将发送者设置为NSButton但实际上它是NSSlider。现在我问对象是否会响应 setAlternateTitle 。虽然NSButton会这样做而NSSlider不会。如果我运行代码并自己执行 respondsToSelector ,它会告诉我对象不会响应该选择器。如果我测试像 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消息时,程序将崩溃,我不确定为什么。在发送消息之前,它不应该执行respondsToSelector吗?

4 个答案:

答案 0 :(得分:149)

首先,方法的名称(它的选择器)包括所有子部分和冒号字符,如mvds所说。

其次,方法-respondsToSelector:不是由运行时调用的,它通常由用户调用(您自己或想要知道委托是否响应协议的可选方法的API) )。

当您向对象发送消息时,运行时将在对象的类中查找该方法的实现(通过对象的isa指针)。这相当于发送-respondsToSelector:,尽管消息本身未被分派。如果在类或其超类中找到方法的实现,则使用传入的所有参数调用它。

如果没有,则运行时为消息提供第二次执行的机会。它将首先将消息+ (BOOL)resolveInstanceMethod:(SEL)name发送到对象的类:此方法允许您在运行时将该方法添加到类中:如果此消息返回YES,则表示它可以重新分发消息。

如果不是,它给消息第三次执行机会,它会向选择器发送- (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类中此方法的实现会引发异常。

答案 1 :(得分:7)

首先,selector不仅是消息的“名称”,而且是后面的内容,即参数及其名称。

因此某些-(void)setAlternateTitle:(NSString*)str的正确选择器将是

@selector(setAlternateTitle:)

:

至于你的问题:如果一个类respondsToSelector()并且你执行了那个选择器,你不应该在发送一个未知选择器时遇到崩溃。您在调试窗口中看到了什么样的崩溃日志?

(ps。为什么不在[slider setAlternateTitle:...]条件块中包含if ( responds ) { ... }?)

答案 2 :(得分:2)

  

“这是因为在消息之前   发送Objective-C将执行   respondsToSelector“。

我猜这不对。如果对象没有响应选择器,它将在运行时崩溃。系统没有自动检查。如果运行时系统进行了检查,那么我们永远不应该将“无法识别的选择器发送到实例”异常。

如果我错了,请让我纠正。

编辑:这不是直接崩溃,但默认结果是进程将被终止。整个序列已在评论和其他答案中解释,所以我不打算再写一遍。

答案 3 :(得分:2)

有一种+instancesRespondToSelector:方法。顾名思义,它会告诉您类的实例是否实现了该方法。

相关问题