实际上,我的情况是我想找到一种简单优雅的方式来调用一个可选的协议方法。
当我有这样一个协议:
@protocol SubModuleProtocol <NSObject>
@optional
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;
- (void)scrollViewDidScroll:(UIScrollView *)scrollView;
@end
推荐的调用样式是:
id <SubModuleProtocol> subModule = xxx;
if ([subModule respondsToSelector:@selector(scrollViewWillBeginDragging:)]) {
[subModule scrollViewWillBeginDragging:nil];
}
我认为如果协议中有很多方法,这种方法太麻烦了。所以我想写一个宏来调用。
首先我使用宏:
#define SAFECALL(object,sel,func)
if ([object respondsToSelector:sel]) {
[object func];
}
你可以使用:
SAFECALL(subModule, @selector(scrollViewWillBeginDragging:), scrollViewWillBeginDragging:nil);
这条路还是有点麻烦。我想要一个这样的宏:
#define SAFECALL(object,func)
if ([object respondsToSelector:**Get Selector from func**]) {
[object func];
}
可以用c分析字符串就可以实现了。但这看起来不是个明智的办法。那么解决这个问题的最好方法是什么呢?或者有比使用marco更好的安全调用方法。
在应用逻辑中使用宏并不理想,但是你可以使用下面的…
#define CALL_IF_RESPONDS_TO_SEL(o,s) if([o respondsToSelector:@selector(s)])
{SEL sel=@selector(s);
IMP imp=[o methodForSelector:sel];
void(*fn)(id,SEL)=(void*)imp;
fn(o,sel);}
这个显然不处理对象消息,除了调用对象上的方法。
如果你经常这样做,你会后悔的。在示例CALL_IF_RESPONDS_TO_SEL(someobj,withParam:andParam:); // <-- does not work as is!
CALL_IF_RESPONDS_TO_SEL(someobj,withParam); // <-- should work
CALL_IF_RESPONDS_TO_SEL(someobj,withParam:); // <-- see, easy bug!
所以协议中可用方法的数量并不麻烦,但是有一个参数或多个参数的方法就麻烦了,因为对于那些简单的函数调用不会像预期的那样工作。
如果你调用的方法总是包含相同数量的消息,那么在宏中包含应用逻辑可以使事情变得更容易,但是像普通方法一样正确地实现协议安全检查仍然更安全,更容易调试。
或者集成以下内容以便能够在方法调用
上使用对象#define CALL_IF_RESPONDS_TO_SEL(o,s,param) if([o respondsToSelector:@selector(s)])
SEL sel = @selector(s);
[o performSelector:sel withObject:param];}
在这种情况下,param
也可以是nil
,选择器s
将以:
结尾。