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

1k views Asked by At

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.

3

There are 3 answers

4
Williham Totland On BEST ANSWER

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.

0
iandotkelly On

Unfortunately I am not whether any of these answers are good. Unfortunately this comes down to purpose - it may not even be intended for you to call the superclass method, sometimes overriding a method is about replacing the method, not chaining your functionality on top of the superclass's functionality.

It comes down to reading the documentation and choosing the right approach.

If this is about a framework that you are implementing and wish to use a consistent approach, then 2 or 3 should be fine. 1 and 4 rely on exceptions - which are not really intended to be used for anything except truly exceptional issues in objective-c.

2
Mats Stijlaart On

In objective c you can define methods in protocols to be required or optional, but your never sure if a class that is conform to a protocol, actually implements that protocol.

So you always have to check if the instance responds to a protocol.
I would choose for option 2, this is the most elegant. When you will make the protocol method optional in the future, this will still be the correct solution.

Option 4 I personally find to much Java-ish.