【问题标题】:How can get method selector from function call string in objective-c?如何从objective-c中的函数调用字符串中获取方法选择器?
【发布时间】:2021-11-28 08:11:42
【问题描述】:

其实我的情况是想找一种简洁优雅的风格来调用可选的protocol方法。

当我有这样的协议时:

@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 更好的方法来进行安全调用。

【问题讨论】:

    标签: ios c objective-c macros


    【解决方案1】:

    将宏用于应用逻辑并不理想,但您可以使用以下内容..

    #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 将以 : 结尾。

    【讨论】:

    • 谢谢你的回答。“performSelector”通常是不够的,因为它最多只允许两个参数。最重要的是我想使用编译器检查参数。“performSelector”和“msg_send” "已经失去了这种能力。
    • 直言不讳,当使用委托设计模式时,尽管被广泛使用,但发送对象仍然是不够的。当涉及对象发送时,我不会使用使事情更难以调试的宏。第一个宏可以扩展为支持多个对象,但调试仍然变得更糟。还使用 respondsToSelector 意味着您没有使用委托设置器,无论如何最好将它们分开。
    猜你喜欢
    • 1970-01-01
    • 2012-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-11
    • 1970-01-01
    • 2011-11-05
    相关资源
    最近更新 更多