views:

2706

answers:

6

Is there a class method equivalent to -respondsToSelector:?

Something like +respondsToSelector:?

The reason I am asking is because by implementing -respondsToSelector: on a class level, I get a compiler warning: "found '-respondsToSelector:' instead of '+respondsToSelector:' in protocol(s)".

The code looks like this:

Class <SomeProtocol> someClass = [someInstance class];

if ([someClass respondsToSelector:@selector(someSelector:)]) {
    someVar = [someClass someSelector:someData];
}
+3  A: 

Well a class method is just a method of the class object, so you should be able to just do this

[MyClass respondsToSelector:@selector(...)]
newacct
I get a compiler warning: "found '-respondsToSelector:' instead of '+respondsToSelector:' in protocol(s)". How do I get rid of this compiler warning?
firstresponder
I can get rid of the compiler warning by dropping the protocol type qualifier '<SomeProtocol>'. Why is that? Is that syntax not correct?
firstresponder
firstresponder: Objective-C is a dynamic language. If you send a message to a `Class` or `id` without qualifying that type further (with a protocol), the compiler assumes that you are doing some kind of responds-to-selector or is-kind-of-class check yourself. However, if you do specify a protocol or (for instances) a specific class, it gets helpful and performs the check for you. Since the protocol you've declared the variable with doesn't have a `+respondsToSelector:` declaration, the compiler raises a warning.
Peter Hosey
A: 

What are you really trying to achieve?

Can it be that you are actually looking for conformsToProtocol or isKindOfClass or even isMemberOfClass?

nicktmro
A: 

I don't know if this is it, but after looking at the docs, I found +(BOOL)instancesRespondToSelector:(SEL)aSelector.

Jorge Israel Peña
Nope, that's separate from the issue of a class directly responding to a method. [NSString class] responds to stringWithFormat:, while an individual NSString instance does not.
BJ Homer
Right, this method is essentially equivalent to -respondsToSelector: without requiring you to have an instance of the class to test against.
Quinn Taylor
+6  A: 

Update after seeing your edit:

A class object responds to respondsToSelector: just fine, as you're probably aware. In a test application, I can do both of the following without any compiler warnings:

NSLog(@"Responds to selector? %i", [MyObject respondsToSelector:@selector(respondsToSelector:)]);
NSLog(@"Responds to selector? %i", [[MyObject class] respondsToSelector:@selector(respondsToSelector:)]);

(Slightly self-referential, I know, but it works).

However, given that you're calling this on a Class, it just doesn't know quite what to do. You've declared protocols, so it assumes that the class only implements those methods. The simplest solution would be to cast someClass as an id for the purpose of calling respondsToSelector:. A somewhat cleaner solution would be to declare your own @protocol which declares +respondsToSelector:(SEL)selector, and then declare someClass as follows:

Class<SomeProtocol, ClassRespondingToSelector> someClass = ...

Finally, be sure to file a bug with Apple at http://bugreporter.apple.com. Include a simple test application so that it's very clear what you're doing. They welcome such bug reports, even if they've been submitted in the past, as it helps them prioritize the fixes.

Final note: this is probably happening because in theory, you could have chosen to implement a root object entirely separate from NSObject, and in that case, it wouldn't respond to -respondsToSelector:. -[NSObject respondsToSelector:] is actually declared in the NSObject protocol, not the class definition. The NSObject protocol is actually where most of what you know as NSObject actually lives. One could argue that +respondsToSelector: should also be in there, but as of now, it's not. And since you've provided a protocol list, and the method isn't in there, it gives you a warning to make sure you know what you're doing.

BJ Homer
+1  A: 

What I think you were asking is: Can you ask a class if it responds to +someMethod or not? In other words, thinking of the Cocoa Touch APIs, you would want:

[ [ UIView class ] respondsToSelector: @selector( buttonWithType: ) ] -> NO
[ [ UIButton class ] respondsToSelector: @selector( buttonWithType: ) ] -> YES

But what I wrote above doesn't work as desired. respondsToSelector: is only about instance methods. (Thus both calls will return NO.) Within the Cocoa APIs there is no equivalent to respondsToSelector: for a class.

You can, however, call class_getClassMethod. If the result is non-NULL, the class method you are asking about is present and you can call it.

escouten
This is false. `respondsToSelector:` works just fine on `Class` objects to report the existence of class methods.
Dave DeLong
I up-vote this dude, because he was actually correct with his `class_getClassMethod` approach. If I have had enough patience to read the entire thread I wouldn't have to reinvent the same solution.
bioffe
A: 

I think I can offer you the solution:

#import "objc/runtime.h"
Class <ContextConfiguration> _customContext= ...
if(class_getClassMethod(_customContext, @selector(MyClassLevelMethodName))
bioffe