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.