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

Что вызывается перед @main?

1.6 Junior🔥 81 комментариев
#UIKit и верстка

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

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

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

Что вызывается перед @main в Swift?

В Swift, особенно начиная с версии 5.3 и появления атрибута @main, процесс запуска приложения стал более декларативным, но под капотом сохраняется сложная цепочка инициализации. Прямого вызова "перед @main" в пользовательском коде нет, так как @main отмечает точку входа (entry point) приложения. Однако, если рассматривать всю последовательность запуска iOS/macOS приложения, можно выделить несколько ключевых этапов, которые происходят до выполнения кода в @main.

1. Загрузка и инициализация исполняемой среды

До того как управление передаётся в main (или аналог с @main), операционная система (iOS/macOS) выполняет ряд низкоуровневых действий:

  • Загрузка исполняемого файла (Mach-O) в память.
  • Динамическая линковка (dyld) — загрузка и связывание динамических библиотек (например, Foundation, UIKit, Swift runtime). Это включает обработку зависимостей, релокацию адресов и загрузку классов Objective-C (если есть).
  • Инициализация Swift runtime — настройка метаданных Swift (типов, протоколов), вызов статических инициализаторов (например, static let или глобальных переменных в Swift). Это происходит автоматически до main.

2. Роль @main и его предшественники

Атрибут @main — это синтаксический сахар, который заменяет явное объявление функции main. Компилятор Swift генерирует точку входа за вас. Например, такой код:

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

Компилятор преобразует его в нечто подобное (упрощённо):

// Сгенерированный код
static func main() -> Void {
    MyApp.main()
}

До @main (в Swift до 5.3 или Objective-C) точка входа определялась явно через функцию main в файле main.m или main.swift:

// Objective-C пример
int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

В этом случае, ничего в пользовательском коде не вызывается перед main, так как main — это самая первая функция, которую вызывает система. Однако, в Swift глобальные переменные и статические инициализаторы могут выполняться до вызова main (технически, они инициализируются во время загрузки среды выполнения).

3. Ключевые этапы до выполнения кода в @main

Если обобщить, вот что происходит "перед" выполнением кода внутри @main (в контексте iOS приложения):

  1. Запуск процесса системой — iOS создаёт процесс и загружает исполняемый файл.
  2. Работа dyld — динамический загрузчик линкует библиотеки, включая Swift runtime и системные фреймворки.
  3. Инициализация Objective-C runtime (если есть) — регистрация классов, категорий, протоколов.
  4. Инициализация Swift runtime — настройка метаданных Swift, вызов статических инициализаторов (например, для глобальных переменных). Например:
    // Этот код выполнится до main/@main
    let globalConstant = SomeClass.initializeSomething()
    
  5. Вызов сгенерированной функции main — компилятор Swift создаёт точку входа, которая вызывает ваш @main тип.

4. Практический пример: статические инициализаторы

В Swift, статические свойства или глобальные переменные могут инициализироваться до @main. Это важно учитывать, так как их побочные эффекты произойдут раньше:

// Глобальная переменная — инициализируется до @main
let appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? ""

@main
struct MyApp: App {
    // Статическое свойство — также инициализируется до main
    static let startupTime = Date()
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

Здесь appVersion и startupTime будут вычислены до выполнения кода в MyApp.

5. Итог

  • Прямого вызова "перед @main" в пользовательском коде нет, так как @main — это объявление точки входа.
  • Фактически, перед выполнением кода в @main происходят системные процессы: загрузка файла, линковка библиотек, инициализация Swift/Objective-C runtime, а также выполнение статических инициализаторов Swift.
  • В современных SwiftUI приложениях с @main, код внутри структуры (например, MyApp) начинает выполняться уже после этой низкоуровневой инициализации.

Понимание этого процесса помогает в отладке сложных проблем запуска, таких как зависания в dyld или ошибки в статических инициализаторах. Для большинства разработчиков достаточно помнить, что глобальные и статические переменные инициализируются до @main, а основная логика приложения стартует внутри него.

Что вызывается перед @main? | PrepBro