Иногда (а при работе с каркасом Cocoa достаточно часто) требуется заместить унаследованный метод, но при этом оставить возможность доступа к замещаемой функциональности.
Для этого используется ключевое слово super. Подобно self, ключевое слово super представляет собой нечто, чему можно отправить сообщение. Но его значение не имеет ничего общего с “этим экземпляром” или любым иным экземпляром. Ключевое слово super основано на классе и означает: “начать поиск для полученного сообщения в суперклассе данного класса” (где “данный класс” представляет собой класс, в котором находится ключевое слово super).
Вы можете делать с super все, что хотите, но его основная цель, как я только что сказал, — доступ к перекрытой функциональности (обычно в самой перекрывающей функции, чтобы получить как перекрытую функциональность, так и некоторые дополнительные возможности).
Предположим, например, что мы определили класс NoisyDog, являющийся подклассом Dog. Когда передается сообщение bark, он лает дважды:
Этот код дважды вызывает реализацию метода 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:, описанный в документации следующим образом:
Документация гласит, что UlViewController является классом, для которого с большой вероятностью потребуется определить подкласс. Документация предполагает, что ваш подкласс класса UlViewController будет перекрывать упомянутый метод, и предупреждает, что если вы это делаете, то “должны вызвать super в некоторой точке вашей реализации”. Фраза “вызвать super” — своего рода сокращение, означающее “передать super тот же вызов и те же аргументы, которые были отправлены вам”.
Скажем, вы перекрываете метод viewDidAppear: в вашем подклассе UlViewController, который называется MyViewController. Ваша реализация может иметь следующий вид:
В результате при вызове viewDidAppear: в экземпляре класса MyViewController мы выполняем как стандартные действия, которые выполняет суперкласс UlViewController в ответ на сообщение viewDidAppear:, так и собственные действия, относящиеся к нашему классу MyViewController. В этом конкретном примере мы даже не знаем, что именно делает класс UlViewController, да нас это и не интересует. Когда документация требует вызывать super при перекрытии — вызывайте super при перекрытии! Пренебрежение этим вызовом, когда его требует документация, может привести к некорректному поведению приложения и является распространенной ошибкой начинающих программистов.