67
- (void)someMethod
{
    if ( [delegate respondsToSelector:@selector(operationShouldProceed)] )
    {
        if ( [delegate operationShouldProceed] )
        {
            // do something appropriate
        }
    }
}

The documentation says:

The precaution is necessary only for optional methods in a formal protocol or methods of an informal protocol

What does it mean? If I use a formal protocol I can just use [delegate myMethod]?

Taho
  • 833
  • 1
  • 10
  • 9

4 Answers4

86

You use it pretty much just when you think you need to: to check to see if an object implements the method you are about to call. Usually this is done when you have an optional methods or an informal protocol.

I've only ever used respondsToSelector when I'm writing code that must communicate with a delegate object.

if ([self.delegate respondsToSelector:@selector(engineDidStartRunning:)]) {
        [self.delegate engineDidStartRunning:self];
    }

You sometimes would want to use respondsToSelector on any method that returns and id or generic NSObject where you aren't sure what the class of the returned object is.

kubi
  • 48,104
  • 19
  • 94
  • 118
  • thanks. I understand now. I noticed you use self.delegate, which is a property. I just use an instance variable: id delegate. what's the difference? Im learning objective-c. thanks again – Taho Sep 12 '10 at 23:37
  • 2
    `self.delegate` is exactly the same as calling `[self delegate]`. In my code there's no difference between `[self.delegate someMethod]` and `[_delegate someMethod]`, but I tend to use dot syntax because it keeps it straight in my mind which variables are local to the method I'm in and which are instance variables. – kubi Sep 12 '10 at 23:55
  • If you're just starting, it will be worth your time to read Apple's guide to Obj-C. http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocProperties.html%23//apple_ref/doc/uid/TP30001163-CH17 – kubi Sep 12 '10 at 23:57
  • one more question: do i need to set delegate = nil in the dealloc and viewDidUnload method?(of the delegate class or the class that implements the delegate or neither?) – Taho Sep 13 '10 at 00:07
  • 1
    No. Delegate properties should almost always be assigned instead of retained. In the vast majority of examples, you don't own the delegate object, so you shouldn't retain or release it. http://stackoverflow.com/questions/918698/why-are-objective-c-delegates-usually-given-the-property-assign-instead-of-retain/918732#918732 – kubi Sep 13 '10 at 00:12
  • It is basically syntatic sugar, but when I have a very regular set of delegate methods I'm using, a preprocessor macro can really make the code more readable. For example: #define NOTIFY_OPTIONAL(sel, id) if ([id respondsToSelector:@selector(sel)]) {[id sel self];} Then in my code: NOTIFY_OPTIONAL(playStarted:, _focusPlayer); – Scott Means Mar 23 '13 at 15:13
  • I am using a delegate in similar fashion: if ([self.delegate respondsToSelector:@selector(engineDidStartRunning:)]) { [self.delegate engineDidStartRunning:self]; } But it still sometimes gives me an error Bad Excess. – Itesh Jan 02 '14 at 06:21
47

Just to add to what @kubi said, another time I use it is when a method was added to a pre-existing class in a newer version of the frameworks, but I still need to be backwards-compatible. For example:

if ([myObject respondsToSelector:@selector(doAwesomeNewThing)]) {
  [myObject doAwesomeNewThing];
} else {
  [self doOldWorkaroundHackWithObject:myObject];
}
Dave DeLong
  • 242,470
  • 58
  • 448
  • 498
15

As kubi mentioned respondsToSelector is normally used when you have a an instance of a method that conforms to a protocol.

// Extend from the NSObject protocol so it is safe to call `respondsToSelector` 
@protocol MyProtocol <NSObject> 

// @required by default
- (void) requiredMethod;

@optional

- (void)optionalMethod;

@end

Given and instance of this protocol we can safely call any required method.

id <MyProtocol> myObject = ... 
[myObject requiredMethod];

However, optional methods may or may not be implemented, so you need to check at runtime.

if ([myObject respondsToSelector:@selector(optionalMethod)]) 
{
     [myObject optionalMethod];
}

Doing this will prevent a crash with an unrecognised selector.


Also, the reason why you should declare protocols as an extension of NSObjects, i.e.

@protocol MyProtocol <NSObject> 

Is because the NSObject protocol declares the respondsToSelector: selector. Otherwise XCode would think that it is unsafe to call it.

Robert
  • 37,670
  • 37
  • 171
  • 213
3

Old question, but I have learned to be very cautios with using stuff like addTarget:@selector(fu:) because the method name is not checked nor included in refactoring by XCODE. This has caused me quite some trouble already. So now I made it a habbit to always embed stuff like addTarget or addObserver in a respondsToSelector-Check like so:

if([self respondsToSelector:@selector(buttonClicked:)]){
    [self.button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
}else{
    DebugLog(@"Warning - a class or delegate did not respond to selector in class %@", self);
} 

I know its not super elegant, but i'd rather add some boilerplate code than have an unexpected crash of my apps in the App Store.

Wirsing
  • 6,713
  • 3
  • 15
  • 13
  • I think "methodName:" is now checked in statements like @selector(methodName:) in xCode now aren't they? – Grezzo Nov 11 '13 at 10:18
  • 1
    @Grezzo - XCode will only check that the selector exists somewhere in your target. So for example if you wrote `@selector(date)` instead of `@selector(data)` XCode will not warn you because the `date` selector exists on `NSDateComponents`. – Robert Feb 03 '14 at 09:17