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