Иногда (а при работе с каркасом Cocoa достаточно часто) требуется заместить унаследованный метод, но при этом оставить возможность доступа к замещаемой функциональности.

Для этого используется ключевое слово super. Подобно self, ключевое слово super представляет собой нечто, чему можно отправить сообщение. Но его значение не имеет ничего общего с “этим экземпляром” или любым иным экземпляром. Ключевое слово super основано на классе и означает: “начать поиск для полученного сообщения в суперклассе данного класса” (где “данный класс” представляет собой класс, в котором находится ключевое слово super).

Вы можете делать с super все, что хотите, но его основная цель, как я только что сказал, — доступ к перекрытой функциональности (обычно в самой перекрывающей функции, чтобы получить как перекрытую функциональность, так и некоторые дополнительные возможности).

 

Предположим, например, что мы определили класс NoisyDog, являющийся подклассом Dog. Когда передается сообщение bark, он лает дважды:

(^implementation NoisyDog : Dog
- (NSString*) bark (
return (NSString stringWithFormat:
[super bark], [super bark]];
}
@end

Этот код дважды вызывает реализацию метода bark из класса super; он объединяет две получающиеся строки в одну с пробелом посредине (используя метод stringWithFormat:) и возвращает ее. Поскольку в классе Dog метод bark возвращает 0"Woof!", в классе NoisyDog метод bark вернет @"Woof ! Woof ! ". Обратите внимание, что рекурсии при этом нет: метод bark из класса NoisyDog не вызывает сам себя.

Приятной особенностью этой архитектуры является то, что, отправив сообщение ключевому слову super, вместо жесткого кодирования @ "Woof! " в методе bark класса NoisyDog мы обеспечиваем возможность сопровождения: если что-то изменится, результат метода bark класса NoisyDog изменится соответственно. Например, если позже метод bark класса Dog станет возвращать @"Arf! ", то результатом метода bark класса NoisyDog станет @"Arf! Arf! ", без каких бы то ни было дальнейших изменений с нашей стороны.

В реальном программировании с помощью каркаса Cocoa вам придется очень часто перекрывать его методы. Например, класс UlViewController, встроенный в каркас Cocoa, реализует метод viewDidAppear:, описанный в документации следующим образом:

- (void)viewDidAppear:(BOOL)animated

Документация гласит, что UlViewController является классом, для которого с большой вероятностью потребуется определить подкласс. Документация предполагает, что ваш подкласс класса UlViewController будет перекрывать упомянутый метод, и предупреждает, что если вы это делаете, то “должны вызвать super в некоторой точке вашей реализации”. Фраза “вызвать super” — своего рода сокращение, означающее “передать super тот же вызов и те же аргументы, которые были отправлены вам”.

Скажем, вы перекрываете метод viewDidAppear: в вашем подклассе UlViewController, который называется MyViewController. Ваша реализация может иметь следующий вид:

- (void) viewDidAppear: (BOOL) animated {
[super viewDidAppear: animated];
// ... Выполняете свои действия ...
}

В результате при вызове viewDidAppear: в экземпляре класса MyViewController мы выполняем как стандартные действия, которые выполняет суперкласс UlViewController в ответ на сообщение viewDidAppear:, так и собственные действия, относящиеся к нашему классу MyViewController. В этом конкретном примере мы даже не знаем, что именно делает класс UlViewController, да нас это и не интересует. Когда документация требует вызывать super при перекрытии — вызывайте super при перекрытии! Пренебрежение этим вызовом, когда его требует документация, может привести к некорректному поведению приложения и является распространенной ошибкой начинающих программистов.


 

 

 

Добавить комментарий