Почему сервисы делают final и используют fileprivate в iOS
Что проверяют
Знаете ли, как в Swift устроена диспетчеризация вызовов, и понимаете ли уровни доступа не по списку из документации, а по тому, что они реально меняют. Вопрос ещё и про то, отличаете ли вы private от fileprivate после того, как private расширили на расширения того же файла.
Как отвечать
final это обещание компилятору, что класс не наследуют, а метод не переопределяют. Обычный метод класса вызывается через таблицу, то есть адрес выбирается в рантайме. Пометив класс final, вы разрешаете прямой вызов и встраивание. Внутри модуля оптимизация по всему модулю часто выводит это сама, а через границу модуля компилятор обязан считать класс открытым для наследования, и там final даёт настоящий выигрыш.
Второй смысл важнее производительности. Сервис с общим состоянием, у которого наследник подменил половину методов, ведёт себя не так, как задумывал автор. final это запрещает и делает поведение типа фиксированным.
fileprivate ограничивает доступ файлом. Он нужен, когда к внутренностям типа обращается что-то другое из того же файла: соседний тип, расширение чужого типа, вспомогательная структура. Для собственных членов типа хватает private, потому что он уже виден в расширениях того же типа в том же файле.
Практический вывод: по умолчанию закрывать всё самым узким уровнем и открывать по необходимости, оставляя публичной только ту часть сервиса, через которую с ним работают. И сразу оговорить, что это не защита данных: уровни доступа проверяет компилятор, в рантайме их нет.
Где спотыкаются
Обещают, что final ускорит всё. Для наследника NSObject и для всего, что помечено @objc или dynamic, вызов всё равно уходит в рантайм Objective-C, и выигрыша не будет.
Путают private и fileprivate и на всякий случай пишут второе везде. Это шире, чем нужно: доступ получает любой тип в файле, а файлы имеют свойство разрастаться.
Третье: делают сервис final и тут же хотят подменять его в тестах наследником. Правильный ход это протокол и другая реализация под ним, а не класс, открытый для наследования ради одного теста.