Search code examples
objective-csuperrespondstoselector

How do you know whether to invoke a superclass method in Objective C


Class Child extends Parent. Parent implements protocol C which has optional methods, including -(void)d. Child has an implementation of -d; should it invoke [super d]?

In other words, what code do I write to invoke [super d] if and only if something will respond to it? Assume that I do not control the implementation of Parent; it may change at any time.

Here are all the ways I have thought of. I am currently using number 4.

Apparently sensible answer 1:

[super d]; // Delete this line if a runtime exception occurs when you try it

This does not work because Parent might implement -d dynamically so this works when you test it and not in the field. Or the implementation of Parent could change so that the result of this test is no longer correct.

Apparently sensible answer 2:

if ([super respondsToSelector:_cmd])
    [super d];

This does not work, because NSObject's implementation of -respondsToSelector will find the implementation in Child and return YES in all cases.

Apparently sensible answer 3:

if ([[self superclass] instancesRespondToSelector:_cmd])
    [super d];

This works if and only if the superclass knows it always implements -d; if instances dynamically determine whether this method is present this technique will not work. Better than 1 in that it will pick up static changes to the implementation of Parent at runtime.

Apparently sensible answer 4:

@try
{
    [super d];
}
@catch (NSException *exception)
{
    NSString *templateReason = [NSString stringWithFormat:
                                @"-[%@ %@]: unrecognized selector sent to instance %p"
                                ,NSStringFromClass([self superclass])
                                ,NSStringFromSelector(_cmd)
                                ,self];
    if (![exception.reason isEqualToString:templateReason])
        @throw exception;
}

Performance of this is poor if the method in the superclass does not exist because computing templateReason and then comparing it to the exception reason is expensive.

This mechanism is fragile because the format of the exception reason string in this case could be altered in a future SDK or runtime release.


Solution

  • None of these things are necessary.

    If you are subclassing some class or other, you already need to know if you are replacing or supplementing behavior.

    In other words, if the implementation exists and you want it done differently, you don't call super.

    If the implementation doesn't exist, you don't call super.

    If the implementation does exist, but you want to supplement it, you call super.

    Addendum:

    Wether the implementation can change at any time isn't relevant for your question; what is important is if the interface changes.

    If the interface is constantly changing, odds are good the class is an exceptionally poor candidate for subclassing, or even use.