1

Is there any way to check whether a protocol contains certain method or whether a method belongs to certain protocol in Objective-C?

I don't think the redirected question is the same as mine. What I want is: [MyProtocol containsSelector:@selector(MySelector)]; Or [MySelector isMethodOfProtocol:@protocol(MyProtocol)];

Community
  • 1
  • 1
Lizhen Hu
  • 814
  • 10
  • 16
  • 1
    @Dominic - That seems like a different question, whether a class conforms to a protocol or not. The question here is whether a protocol contains a particular method or not. I'm just unclear as to _why_ Lizhen needs this, as this strikes me as something that doesn't require any runtime checks. You can determine this at compile time. – Rob Jun 17 '16 at 07:59
  • I think the only way to check is with `respondsToSelector`, and to use it you need an instance of the protocol (`something.delegate` in my answer). If you don't want to keep the delegate if `respondsToSelector` returns `NO`, you just have to do is `delegate = nil;` – AnthoPak Jun 17 '16 at 09:16
  • @Rob - Here's what I'm going to do: If the selector is contained in a certain protocol, it will be forwarded. If not, nothing happened. – Lizhen Hu Jun 17 '16 at 09:30
  • @Dominic Could you undo your redirection? Since they are two different question :) – Lizhen Hu Jun 17 '16 at 10:08
  • @LizhenHu now you have edited your question and made it clearer, yes you are correct (I have deleted the comment) – Dominic Jun 17 '16 at 11:07
  • @Dominic Thanks, actually I mean the header of the question, which says **"This question may already have an answer here..."**, still there :) – Lizhen Hu Jun 17 '16 at 11:11

4 Answers4

2

See the Objective-C runtime functions

Protocol *objc_getProtocol(const char *name)

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

The documentation can, at the time of this writing, be found here.

Avi
  • 7,469
  • 2
  • 21
  • 22
  • This is what I want! Thanks, @Avi :) However, my vote on your answer can't be displayed right now due to my poor reputation :( – Lizhen Hu Jun 17 '16 at 09:54
2

If you know the name of the method, here is what you can do :

First set the delegate of the protocol. Then, check if the method belongs to the protocol as this :

if ([something.delegate respondsToSelector:@selector(someMethodToCheck)])
AnthoPak
  • 4,191
  • 3
  • 23
  • 41
  • Here's what I'm going to do: If the selector is contained in a certain protocol, it will be forwarded. If not, nothing happened. So your answer can't do the job in my case. Thanks though :) – Lizhen Hu Jun 17 '16 at 08:57
  • What do you mean by "it will be forwarded" ? `respondsToSelector` doesn't perform the selector, so if it returns YES, let's perform it, otherwise, do nothing. Am I wrong ? – AnthoPak Jun 17 '16 at 09:03
  • I am doing this in `-forwardingTargetForSelector:`, and this method can accept other selectors, in addition to those belonging to MyProtocol. And I just want to forward the latter ones. – Lizhen Hu Jun 17 '16 at 09:38
  • That only checks whether the delegate implements it, it doesn't tell you if the method is part of the protocol. – Lee Ann Rucker Mar 19 '20 at 18:06
1

Here is a small code snippet I am using right now (thanks to Avi's answer above):

- (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;
}

You can move this to a category on NSObject too, if you use forwarding extensively.

Community
  • 1
  • 1
Ayush Goel
  • 3,134
  • 27
  • 36
1

Here is a function I found Apple using:

#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;
}

Use like this:

- (id)forwardingTargetForSelector:(SEL)aSelector{
    if(MHFProtocolHasInstanceMethod(@protocol(UITableViewDelegate), aSelector)){
    ...
malhal
  • 26,330
  • 7
  • 115
  • 133