Что делает ключевое слово `static` в Swift?

Ответ

Ключевое слово static в Swift объявляет члены типа (свойства и методы), которые принадлежат самому типу, а не какому-либо его экземпляру. Доступ к ним осуществляется через имя типа.

Основное использование:

class Logger {
    // Статическое свойство — общее для всего типа (аналог "классовой переменной")
    static let shared = Logger()
    static var logLevel: LogLevel = .info

    // Статический метод — вызывается на типе, а не на экземпляре
    static func log(_ message: String) {
        print("[\(logLevel)] \(message)")
    }

    private init() {} // Скрытый конструктор для синглтона
}

// Использование БЕЗ создания экземпляра класса Logger
Logger.logLevel = .debug
Logger.log("Приложение запущено") // Вывод: [debug] Приложение запущено

let loggerInstance = Logger.shared // Доступ к синглтону через static свойство

Важные детали:

  • В классах: Объявление с static является синонимом final class. Такие члены не могут быть переопределены в подклассах.
    class Vehicle {
        static func description() { print("Транспортное средство") }
        class func adjustableDescription() { print("Настраиваемое описание") } // Можно переопределить
    }
    class Car: Vehicle {
        // override static func description() { } // Ошибка компиляции: нельзя переопределить
        override class func adjustableDescription() { print("Автомобиль") } // OK
    }
  • В структурах и перечислениях: static используется без ограничений, так как эти типы не поддерживают наследование.
  • Область видимости: Статические свойства инициализируются лениво и гарантированно один раз (потокобезопасно), что делает их удобными для реализации синглтонов и shared-ресурсов.

Ответ 18+ 🔞

Слушай, вот этот твой static в Swift — это ж как та общая заначка на всех, которую спиздить нельзя, потому что она приколочена к полу, блядь. Ну, то есть, это члены, которые принадлежат самому типу, а не какому-то отдельному экземпляру. Обращаешься к ним прямо по имени типа, даже создавать ничего не надо. Красота, ёпта!

Смотри, как это работает, на живом примере:

class Logger {
    // Вот это статическое свойство — общее на всю твою программу. Классовая переменная, блядь.
    static let shared = Logger()
    static var logLevel: LogLevel = .info

    // А это статический метод. Вызываешь на классе, и всё, ни одного экземпляра.
    static func log(_ message: String) {
        print("[(logLevel)] (message)")
    }

    private init() {} // Приватный конструктор, чтобы синглтон был синглтоном, а не распиздяйством.
}

// Используем БЕЗ создания экземпляра, в натуре!
Logger.logLevel = .debug
Logger.log("Приложение запущено") // Выведет: [debug] Приложение запущено

let loggerInstance = Logger.shared // А вот так получаешь тот самый единственный экземпляр через static.

А теперь важные нюансы, чтобы не обосраться:

  • В классах: Когда ты пишешь static — это всё, приехали. Это как final class. Переопределить эту хуйню в подклассе нельзя, ни хера. Хоть тресни.
    class Vehicle {
        static func description() { print("Транспортное средство") }
        class func adjustableDescription() { print("Настраиваемое описание") } // А вот это — можно переопределить!
    }
    class Car: Vehicle {
        // override static func description() { } // Ошибка компиляции! Нельзя, блядь! Final, ёпта!
        override class func adjustableDescription() { print("Автомобиль") } // А это — пожалуйста, на здоровье.
    }
  • В структурах и перечислениях: Тут вообще красота, потому что наследования нет. Пихай static куда хочешь, и ни у кого вопросов не будет.
  • Область видимости и безопасность: Вот это вообще охуенно. Статические свойства инициализируются лениво и гарантированно один раз, да ещё и потокобезопасно. Идеально, чтобы делать синглтоны или всякие общие ресурсы, которые на всех одни. Никаких гонок, никакого пиздеца.