How to safely send @optional protocol messages that might not be implemented

@optional methods in Objective C protocols

Objective C 2.0 added support for @optional methods in protocols. Whatever class conforms to the protocol, it won’t be forced to implement “empty” methods if it doesn’t need them. This is certainly handy for the client conforming to the protocol. Unfortunately, it makes life miserable on the other side.

Handling non implemented @optional methods in Cocoa

Assume you have a class called  SimpleStateMachine that defines the following delegate protocol:

The delegate is free to implement the methods that are necessary and ignore those that aren’t. However, the class SimpleStateMachine cannot blindly send those messages to its delegate, as if a single one is not implemented, the application will crash.

I was expecting the runtime to detect if an @optional method is not implemented, and sending it to nil. Not so.

Code, toil and tears

Since there aint such thing as free lunch, what are you options? It seems like you must manually check respondsToSelector: before sending the message every single time. This is not only tedious, but substantially uglifies your code.

A better option would be to define a HOM method in a category on NSObject, as suggested by Peter N. Lewis in StackOverflow:

You will soon need a withObject: version:

and maybe a withObject:withObject: one.

A slightly more elegant and far more flexible solution: enter Blocks

Blocks allow to conditionally perform any code based on the existence of an implementation of a given method:

By using this addition to NSObject, you can conditionally execute any @optional method, no matter how many parameters it might have.

Your code might look like this:

I’m still looking for a less verbose solution, but this seems reasonably satisfactory by now.


Acerca de Fernando Rodriguez

Fundador & Editor Jefe de CocoaMental, Fernando Rodríguez (@frr149 & Linkedin) es desarrollador & un experto en la enseñanza de máxima calidad en programación y desarrollo para dispositivos iOS, Cocoa Touch, Objective C, Swift, Python, entre otros, aunque su mejor carta de presentación, es la opinión de sus alumnos: http://keepcoding.io/es/testimonio/ CLO en KeepCoding & Arunovo. Instructor de iOS Avanzado del Big Nerd Ranch. Profesor Asociado de la U-tad, autor invitado de revistas como iPhoneWorld, Applesfera.com & ponente habitual en conferencias dentro y fuera de España (iOSDevUK, CodeMotion, BCNDevCon, etc). En sus vidas anteriores fue un nerd de Python y Django, mago de Smalltalk, y para su pesar, galeote de C++ y un gran cocinero.

Share this:

2 comments, add yours.

Emmanuel Gomez

Pardon me for being blunt, but in what way is your final, block-based solution superior to the original?

The original is (effectively):

if ([self.delegate respondsToSelector:@selector(aSelector)])
[self.delegate aSelector];

Your block based solution is more code:

[(NSObject*)self.delegate performBlock:^{
[self.delegate simpleStateMachineWillMoveFromState:self._currentState toState:newState];
} ifRespondsTo:@selector(simpleStateMachineWillMoveFromState:toState:)];

I think the original is better. I agree that performSelectorIfResponds: is a little ungainly but at least it only requires typing the method name once.

Narciso Cerezo

Hi Fernando,
Thanks for this approach, I find the block solution the most elegant. However, if the selector returns a value that you must use in your flow, or you must take action if the selector is not implemented, if falls a bit short.
This might not be a perfect solution either, but I think it is a good addition for such a case:

– (void)performBlock:(void (^)(void))block ifRespondsTo:(SEL) aSelector {
[self performBlock:block ifRespondsTo:aSelector elsePerformBlock:nil];

– (void)performBlock:(void (^)(void))block ifRespondsTo:(SEL) aSelector elsePerformBlock:(void (^)(void))elseBlock {
if ([self respondsToSelector:aSelector]) {
else if( elseBlock ) {

This way you could write something like:

[(NSObject*)self.delegate performBlock:^{
[self.delegate simpleStateMachineWillMoveFromState:self._currentState toState:newState];
} ifRespondsTo:@selector(simpleStateMachineWillMoveFromState:toState:) elsePerformBlock:^{
// do something


Leave a comment