如何在 Objective-C 中以编程方式检查协议是不是包含某些方法?

Posted

技术标签:

【中文标题】如何在 Objective-C 中以编程方式检查协议是不是包含某些方法?【英文标题】:How to check whether a protocol contains certain method programatically in Objective-C?如何在 Objective-C 中以编程方式检查协议是否包含某些方法? 【发布时间】:2016-06-17 07:25:07 【问题描述】:

Objective-C有什么方法可以检查一个协议是否包含某个方法或某个方法是否属于某个协议?

我认为redirected question 和我的不一样。我想要的是: [MyProtocol containsSelector:@selector(MySelector)]; 或者 [MySelector isMethodOfProtocol:@protocol(MyProtocol)];

【问题讨论】:

@Dominic - 这似乎是一个不同的问题,一个类是否符合协议。这里的问题是协议是否包含特定方法。我只是不清楚为什么 Lizhen 需要这个,因为这让我觉得它不需要任何运行时检查。您可以在编译时确定这一点。 我认为检查的唯一方法是使用respondsToSelector,并且要使用它,您需要一个协议实例(something.delegate 在我的回答中)。如果您不想在respondsToSelector 返回NO 时保留委托,您只需要做的是delegate = nil; @Rob - 这是我要做的:如果选择器包含在某个协议中,它将被转发。如果没有,什么都没有发生。 @Dominic 你能撤消你的重定向吗?因为它们是两个不同的问题:) @LizhenHu 现在您已经编辑了您的问题并使其更清晰,是的,您是正确的(我已删除评论) 【参考方案1】:

查看 Objective-C 运行时函数

Protocol *objc_getProtocol(const char *name)

struct objc_method_description *protocol_copyMethodDescriptionList(Protocol *p, BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *outCount)

在撰写本文时,可以在 here 找到该文档。

【讨论】:

这就是我想要的!谢谢,@Avi :) 但是,由于我的声誉不佳,我现在无法显示我对您的答案的投票:(【参考方案2】:

如果你知道方法的名称,你可以这样做:

首先设置协议的委托。 然后,检查该方法是否属于该协议:

if ([something.delegate respondsToSelector:@selector(someMethodToCheck)])

【讨论】:

这是我要做的:如果选择器包含在某个协议中,它将被转发。如果没有,什么都没有发生。因此,在我的情况下,您的回答无法胜任。不过谢谢:) “将被转发”是什么意思? respondsToSelector 不执行选择器,所以如果它返回 YES,让我们执行它,否则,什么都不做。我错了吗? 我在-forwardingTargetForSelector:做这个,这个方法除了属于MyProtocol的,还可以接受其他的选择器。我只想转发后者。 只检查委托是否实现它,它不会告诉您该方法是否是协议的一部分。【参考方案3】:

这是我现在正在使用的一个小代码 sn-p(感谢上面的Avi's answer):

- (BOOL)isSelector:(SEL)selector
        ofProtocol:(Protocol *)protocol 
  unsigned int outCount = 0;
  struct objc_method_description *descriptions
  = protocol_copyMethodDescriptionList(protocol,
                                       YES,
                                       YES,
                                       &outCount);
  for (unsigned int i = 0; i < outCount; ++i) 
    if (descriptions[i].name == selector) 
      free(descriptions);
      return YES;
    
  
  free(descriptions);
  return NO;

如果您广泛使用转发,您也可以将其移至 NSObject 上的一个类别。

【讨论】:

【参考方案4】:

这是我发现 Apple 使用的一个函数:

#import <objc/runtime.h>

BOOL MHFProtocolHasInstanceMethod(Protocol *protocol, SEL selector) 
    struct objc_method_description desc;
    desc = protocol_getMethodDescription(protocol, selector, NO, YES);
    if(desc.name)
        return YES;
    
    desc = protocol_getMethodDescription(protocol, selector, YES, YES);
    if(desc.name)
        return YES;
    
    return NO;

这样使用:

- (id)forwardingTargetForSelector:(SEL)aSelector
    if(MHFProtocolHasInstanceMethod(@protocol(UITableViewDelegate), aSelector))
    ...

【讨论】:

以上是关于如何在 Objective-C 中以编程方式检查协议是不是包含某些方法?的主要内容,如果未能解决你的问题,请参考以下文章

如何在Objective-C中以编程方式而不是由用户控制UISwitch的状态?

如何在 Objective-C 中以编程方式添加特定大小的 UIImageView。我也有同一个类的 xib 文件,但我不想使用它

如何在 Objective-C 控制器中以编程方式加载用 swift 编写的自定义 XIB 视图

在 Objective-C Xcode 5 中以编程方式创建视图

基于coreData信息在objective-c中以编程方式创建图像

在 Objective-C 中以动态和编程方式调整 UIView 的大小