Класс Child расширяет Parent.Родитель реализует протокол C, который имеет необязательные методы, включая -(void)d
.Ребенок имеет реализацию -d
;должен ли он вызывать [super d]
?
Другими словами, какой код я пишу для вызова [super d]
тогда и только тогда, когда на него что-то ответит?Предположим, что я не контролирую реализацию Parent;это может измениться в любое время.
Вот все способы, о которых я думал.В настоящее время я использую номер 4.
Очевидно разумный ответ 1:
[super d]; // Delete this line if a runtime exception occurs when you try it
Это не работает, потому что родитель может реализовать -d динамически, так что это работает, когда вы тестируетеэто и не в поле.Или реализация Parent может измениться, так что результат этого теста больше не будет правильным.
Видимо разумный ответ 2:
if ([super respondsToSelector:_cmd])
[super d];
Это не работает,потому что реализация -respondsToSelector в NSObject найдет реализацию в Child и вернет YES во всех случаях.
Видимо разумный ответ 3:
if ([[self superclass] instancesRespondToSelector:_cmd])
[super d];
Это работает, если и толькоесли суперкласс знает, что он всегда реализует -d;если экземпляры динамически определяют, присутствует ли этот метод, этот метод не будет работать.Лучше, чем 1, поскольку он будет воспринимать статические изменения в реализации Parent во время выполнения.
Очевидно разумный ответ 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;
}
Производительность этого плохаяесли метод в суперклассе не существует, потому что вычисление templateReason и последующее сравнение его с причиной исключения является дорогостоящим.
Этот механизм хрупок, поскольку формат строки причины исключения в этом случае может быть изменен в будущем.SDK или выпуск времени выполнения.