← Назад к вопросам

В какой момент инициализируется static?

1.6 Junior🔥 152 комментариев
#Многопоточность и асинхронность#Язык Swift

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Инициализация статических переменных в iOS (Swift/Objective-C)

В iOS-разработке на Swift и Objective-C момент инициализации static переменных имеет свои особенности в зависимости от контекста их объявления.

1. Статические переменные внутри функций

В Swift статические переменные внутри функций инициализируются лениво (lazily) при первом вызове функции, где они объявлены. Это гарантируется языком и является потокобезопасным.

func createID() -> Int {
    static var counter = 0 // Инициализируется только при первом вызове createID()
    counter += 1
    return counter
}

print(createID()) // 1 - здесь происходит инициализация counter = 0
print(createID()) // 2 - counter уже инициализирован

В Objective-C аналогом является static переменная внутри функции, которая инициализируется при первом выполнении этой строки кода в рамках вызова функции.

- (int)generateID {
    static int counter = 0; // Инициализируется при первом вызове generateID
    counter++;
    return counter;
}

2. Статические свойства и переменные уровня типа

В Swift статические свойства (static let/var) в классах, структурах и перечислениях также по умолчанию лениво инициализируются при первом обращении к ним. Это поведение гарантирует потокобезопасность.

class DataManager {
    static let shared = DataManager() // Ленивая инициализация при первом обращении
    static var cache: [String: Any] = [:] // Аналогично
}

// Инициализация произойдет здесь:
let manager = DataManager.shared

Исключение: если добавить модификатор @objc dynamic, то инициализация может произойти раньше, так как требуется интеграция с Objective-C runtime.

3. Глобальные статические переменные

Глобальные переменные (вне любого типа) в Swift ведут себя аналогично статическим свойствам — ленивая потокобезопасная инициализация.

let appVersion = Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "1.0"
// Инициализируется при первом использовании в коде

4. Отличие от class var (только Swift)

Для вычисляемых свойств класса можно использовать class var, которые не хранят значение, а вычисляются каждый раз.

class MyClass {
    class var version: String { 
        return "1.0" // Вычисляется при каждом обращении
    }
}

5. Взаимодействие с Objective-C

В Objective-C статические переменные уровня файла (глобальные) инициализируются до вызова main() или во время загрузки модуля (framework/library). Порядок инициализации между модулями не гарантирован.

// MyModule.m
static NSString *const apiKey = @"ABC123"; // Инициализируется при загрузке модуля

Ключевые моменты:

  • Ленивая инициализация — основной принцип для Swift, обеспечивающий оптимизацию.
  • Потокобезопасность — Swift гарантирует безопасное ленивое создание статических переменных.
  • Момент инициализации зависит от типа переменной: глобальные, свойства типа, локальные в функциях.
  • Отличие от dispatch_once — в Objective-C для синглтонов часто использовался dispatch_once, который в Swift заменен ленивой инициализацией статических свойств.

Практический пример синглтона с гарантированной ленивой инициализацией:

final class NetworkManager {
    static let shared = NetworkManager()
    
    private init() {
        // Настройка менеджера
    }
    
    func fetchData() { /* ... */ }
}

// Использование:
NetworkManager.shared.fetchData() // Здесь произойдет инициализация shared

Таким образом, в iOS-разработке момент инициализации статических переменных преимущественно отложенный (ленивый) и потокобезопасный, что соответствует современным практикам управления памятью и производительности.