Reputation: 3616
I have my protocol defined. I have mentioned two of my protocol methods as optional. During run-time, how can I find out whether the particular method is optional or not? Is there any way to find out that?
Upvotes: 6
Views: 781
Reputation: 21373
This ought to do what you want:
BOOL MethodInProtocolIsRequired(Protocol *protocol, SEL methodSelector)
{
struct objc_method_description methodDesc = protocol_getMethodDescription(protocol, methodSelector, YES, YES);
return methodDesc.name != NULL;
}
Note that I'm not commenting on the advisability of using this in shipping code, especially since you haven't explained why you want to do this. Also note that this function will return NO when given a selector for a method that the protocol doesn't contain. That's basically reasonable (after all, if a protocol doesn't contain a method, it's not required!), but you could add sophistication to the function by checking to see if the protocol contains the method as an optional method and return something different for all three scenarios (required, optional, not-in-protocol).
EDIT: Simple test program here: https://gist.github.com/4381753
Upvotes: 12
Reputation:
(I don't know the answer off of the top of my head. 1 minute of googling helped me out.)
You can do this using the protocol_copyMethodDescriptionList()
function which is part of the Objective-C runtime library (libobjc). The 2nd argument of this function is a Boolean flag that indicates if the methods to be copied in the protocol are required. So, if a method is in the list returned by this function (called using the appropriate arguments), then it is a required method.
SEL sctr = @selector(isThisMethod:requiredIn:theProtocol:);
struct objc_method_description *methods;
unsigned int nMethods;
methods = protocol_copyMethodDescriptionList(
objc_getProtocol("MyProtocolName"), // or @protocol(MyProtocolName) if you don't need this kind of dynamism
YES, // required?
YES, // instance method? (in general, protocols declare instance methods)
&nMethods
);
BOOL isRequired = NO;
int i;
SEL s;
const char *sctrStr = sel_getName(sctr);
for (i = 0; i < nMethods; i++) {
s = methods[i].name;
const char *sStr = sel_getName(s);
if (strcmp(sctrScr, sStr) == 0) {
isRequired = YES;
break;
}
}
free(methods);
if (isRequired) {
// required
} else {
// optional
}
So, this is possible, but it's a bit of an overkill, and as I already mentioned in my comment on your question, you should not test for a method being optional or required, you should test for an instance responding to a particular selector.
Edit: yes, instead of copying the whole universe, I should have read furhter in the documentation. As Andrew Madsen pointed out, this can be reduced to a few lines:
struct objc_method_description method;
method = protocol_getMethodDescription(
objc_getProtocol("MyProtocolName"), // or @protocol(MyProtocolName)
@selector(isThisSelector:required:)
YES, // required?
YES // instance method?
);
if (method.name != NULL) {
// required
} else {
// optional
}
Upvotes: 3