Каковы преимущества использования базового класса в Swift?
Что проверяют
Вопрос с подвохом: интервьюер ждёт не восхваления наследования, а понимания, когда базовый класс оправдан, а когда в Swift лучше протокол. Следом обычно спрашивают про протоколы с реализацией по умолчанию и ваш опыт с BaseViewController.
Как отвечать
Назовите реальные преимущества класса перед альтернативами:
- общее хранимое состояние: протокол и расширение не добавляют хранимые свойства, а базовый класс может. Если у наследников одинаковые поля и жизненный цикл, класс честнее;
- вызов родительской реализации:
overrideсsuper.viewDidLoad()дополняет поведение, а не заменяет его целиком. У протокола такого механизма нет; - UIKit: фреймворк построен на наследовании,
UIViewController,UIView,UITableViewCellвы наследуете всё равно; - ссылочная семантика: объект один, его можно сравнить через
===и передать делегатом поweak-ссылке; - динамическая диспетчеризация: подкласс подменяет поведение там, где код работает с типом родителя.
Затем покажите ограничения языка. Наследоваться можно только от одного класса, структуры и перечисления не наследуются вообще, а view в SwiftUI это структуры. Ключевого слова abstract нет: «абстрактный» метод с fatalError() внутри ловит ошибку только в рантайме, а требование протокола проверит компилятор. Классы, не рассчитанные на наследование, помечают final: это запрещает переопределение и позволяет вызывать методы напрямую, без таблицы.
Сильный вывод: базовый класс берут для общего состояния и точек расширения во фреймворке, поведение без состояния выносят в протокол с расширением, остальное собирают композицией.
Где спотыкаются
Раздувают BaseViewController до сотни методов: аналитика, клавиатура, алерты, загрузка. Каждый экран получает всё сразу, а правка одного метода задевает всё приложение. Это проблема хрупкого базового класса.
Не знают, как диспетчеризуются методы расширения протокола. Если метод объявлен только в extension, а не в самом протоколе, через переменную типа протокола вызовется версия по умолчанию, даже если тип реализовал свою.
Называют множественное наследование проблемой Swift. Его здесь нет, эту роль играют протоколы.