为什么在obj-c中调用该方法时,未实现的可选协议方法会导致运行时错误?

时间:2009-06-22 19:18:07

标签: objective-c

我有两个类可以作为第三个类的委托,并且都实现完全由可选方法构成的正式协议。其中一个类实现了所有内容,而另一个类只实现了我关心的几个方法。但是,在运行时,当我让第二个类充当第三个类的委托,并且第三个类最终调用该委托上的一个未实现的可选方法时,我得到一个运行时错误,主要是说“Target没有响应这个消息选择器。“我认为objective-c正确地处理了这个案例,并且如果该方法实际上没有在类上定义那么它就什么都不做。可能会有一些我想念的东西吗?

4 个答案:

答案 0 :(得分:33)

当您调用委托的可选方法时,您需要确保它在调用之前响应选择器:

if ([delegate respondsToSelector:@selector(optionalMethod)])
    [delegate optionalMethod];

答案 1 :(得分:10)

可选的协议方法只是意味着实现协议的对象不必实现所讨论的方法 - 然后被调用者必须在调用之前检查对象是否实现了该方法(否则你会崩溃,如你所注意到的)。这些NSObject HOM类别可能会有所帮助:

@implementation NSObject (Extensions)

- (id)performSelectorIfResponds:(SEL)aSelector
{
    if ( [self respondsToSelector:aSelector] ) {
        return [self performSelector:aSelector];
    }
    return NULL;
}

- (id)performSelectorIfResponds:(SEL)aSelector withObject:(id)anObject
{
    if ( [self respondsToSelector:aSelector] ) {
        return [self performSelector:aSelector withObject:anObject];
    }
    return NULL;
}

@end

然后你就可以做到:

[delegate performSelectorIfResponds:@selector(optionalMethod)];

答案 2 :(得分:4)

此块解决方案效果很好,一旦你的头脑缠绕着正在发生的事情。我添加了一个BOOL结果,因为我希望能够有条件地运行几个可选方法中的一个。如果您尝试实施此解决方案,请参阅以下提示:

首先,如果您还没有遇到扩展/类别,只需将其添加到类的顶部,在现有的类定义外部。根据您放置的位置,它将是公共或私人扩展。

@implementation NSObject (Extensions)
// add block-based execution of optional protocol messages
-(BOOL) performBlock:(void (^)(void))block ifRespondsTo:(SEL) aSelector
{
    if ([self respondsToSelector:aSelector]) {
        block();
        return YES;
    }
    return NO;
}
@end

其次,以下是您从代码中调用它的方式:

BOOL b = [(NSObject*)self.delegate performBlock:^{
    // code to run if the protocol method is implemented
} 
ifRespondsTo:@selector(Param1:Param2:ParamN:)];

Param1:Param2:ParamN:替换为协议方法的每个参数的名称。每一个都应以冒号结束。 因此,如果您的协议方法如下:

-(void)dosomething:(id)blah withObj:(id)blah2 andWithObj(id)blah3;

最后一行看起来像这样:

ifRespondsTo:@selector(dosomething:withObj:andWithObj:)];

答案 3 :(得分:1)

块可能提供更好的解决方案。它们允许基于给定方法的实现的存在有条件地执行任何代码:

-(void) performBlock:(void (^)(void))block ifRespondsTo:(SEL) aSelector{
    if ([self respondsToSelector:aSelector]) {
        block();
    }
}

通过对NSObject使用此添加,您可以有条件地执行任何@optional方法,无论它有多少参数。

请参阅How to safely send @optional protocol messages that might not be implemented