Для чего используется модификатор `final` для класса в Swift?

Ответ

final — это модификатор класса, который запрещает наследование от этого класса (создание подклассов). Его также можно применять к отдельным методам и свойствам, чтобы предотвратить их переопределение в подклассах.

Синтаксис:

// 1. Final класс
final class NetworkManager {
    // Этот класс нельзя унаследовать
    func fetchData() { /* ... */ }
}
// Ошибка компиляции: Inheritance from a final class 'NetworkManager'
// class SpecialNetworkManager: NetworkManager { }

// 2. Final метод в обычном классе
class Vehicle {
    final func startEngine() { // Этот метод нельзя переопределить
        print("Engine started")
    }
}
class Car: Vehicle {
    // Ошибка компиляции: Instance method overrides a 'final' instance method
    // override func startEngine() { }
}

Зачем использовать final:

  1. Защита от непреднамеренных изменений: Гарантирует, что критически важная логика класса (например, синглтон или класс, управляющий состоянием) не будет изменена через наследование.
  2. Улучшение производительности: Компилятор может применять агрессивные оптимизации (например, прямой вызов методов вместо динамической диспетчеризации), так как ему известно, что метод не будет переопределен.
  3. Упрощение архитектуры: Явно указывает на то, что класс не был спроектирован для расширения через наследование, поощряя композицию вместо наследования.
  4. Сокращение времени компиляции: Компилятору требуется меньше анализа для final-классов и методов.

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

Ответ 18+ 🔞

Слушай, а вот этот твой final — это ж такая штука, которая говорит: «Нас, блядь, не трожь!». Ну, в хорошем смысле. Представь себе класс — здоровенный такой, отъевшийся менеджер, который всё делает по-своему, и ему насрать на твои хотелки его переделать.

Вот смотри, как это выглядит, ёпта:

// 1. Final класс — неприступная крепость, блядь
final class NetworkManager {
    func fetchData() { /* ... */ }
}
// Пытаешься унаследоваться — получаешь по ебалу от компилятора:
// class SpecialNetworkManager: NetworkManager { } // Inheritance from a final class 'NetworkManager' — НИХУЯ!

// 2. Final метод — конкретный кусок логики, который зацементировали
class Vehicle {
    final func startEngine() { // Этот метод — догма, ебать его в сраку
        print("Engine started")
    }
}
class Car: Vehicle {
    // override func startEngine() { } // Instance method overrides a 'final' instance method — опять нихуя!
}

А нахуя это всё, спросишь?

  1. Чтобы не накосячили, распиздяи. Есть класс, который, например, синглтон или там состояние приложения держит. Его трогать — себе дороже. final говорит: «Руки прочь, пидарас шерстяной, я тут сам всё знаю».
  2. Чтобы быстрее работало, ёбта. Компилятор, видя final, расслабляется. Ему не надо думать, а вдруг метод переопределят. Он сразу знает, куда прыгать, и делает всё в разы шустрее. Оптимизации, блядь, агрессивные включает.
  3. Архитектуру не еби. Это такой намёк другим разработчикам (и себе будущему, который всё забудет): «Этот класс не для того, чтобы от него плодиться. Используй композицию, долбоёб, а не наследование». Просто и со вкусом.
  4. Чтоб компилировалось быстрее. Меньше ему анализировать — быстрее получишь результат. Всё логично, как два пальца обоссать.

Так что, совет мой, как старого пердуна: делай классы final по умолчанию, особенно всякие утилитарные штуки — менеджеры, сервисы, фабрики. А final снимай только тогда, когда прям специально задумал, что от этого класса будут дети плодиться. Не усложняй себе жизнь, в рот меня чих-пых!