Avatar ·

Работают ли приложения на Swift в macOS 10.9 / iOS 7 и более старых версиях?

Всем привет! Я только начал изучать Swift и пишу своё первое приложение под macOS. У меня возникла проблема: мой проект собирается и отлично работает на macOS 10.15 (Catalina), но когда я попытался запустить его на старом MacBook с OS X 10.9 (Mavericks), он просто вылетает при запуске с ошибкой «dyld: Library not loaded». Я начал копать и понял, что это связано с использованием Swift. В Xcode я выбрал минимальную версию развёртывания (Deployment Target) как 10.9, но приложение всё равно не запускается. Я использую Swift 5 и Xcode 12. Вот пример простого кода, который я использую: ```swift import Cocoa class ViewController: NSViewController { override func viewDidLoad() { super.viewDidLoad() let message = "Привет, мир!" print(message) let numbers = [1, 2, 3, 4, 5] let doubled = numbers.map { $0 * 2 } print(doubled) } } ``` Всё работает отлично на новых системах, но на 10.9 — краш. Подскажите, пожалуйста, реально ли вообще запускать приложения, написанные на Swift, на старых версиях macOS (10.9 и ниже) и iOS (7 и ниже)? Может быть, нужно что-то дополнительно подключать или настраивать? Или Swift изначально не поддерживает такие старые системы? Заранее спасибо за помощь! <<>>

Краткий ответ: да, но с ограничениями

Приложения, написанные на Swift, могут работать на macOS 10.9 и iOS 7, но только при соблюдении нескольких важных условий. Дело в том, что Swift runtime (библиотеки, необходимые для выполнения Swift-кода) не встроены в эти старые системы. Apple начала включать Swift runtime в состав операционной системы только с macOS 10.14.4 (Mojave) и iOS 12.2. На более старых версиях runtime нужно добавлять вручную.

Почему ваше приложение падает?

Ошибка dyld: Library not loaded возникает именно потому, что система не находит библиотеки Swift runtime (libswiftCore.dylib и другие). Когда вы собираете приложение в Xcode, компилятор генерирует код, который динамически подгружает эти библиотеки. Если их нет в системе, приложение не запускается.

Решение: встраивание Swift runtime в приложение

Чтобы приложение работало на старых системах, нужно встроить (embed) Swift runtime непосредственно в ваш .app-пакет. Вот пошаговая инструкция:

  1. Проверьте настройки проекта в Xcode:
    • Выберите ваш проект в навигаторе.
    • Перейдите в Build Settings вашей целевой сборки (target).
    • Найдите параметр Always Embed Swift Standard Libraries.
    • Установите его в Yes.

    Это заставит Xcode скопировать все необходимые Swift-библиотеки внутрь вашего приложения.

  2. Убедитесь, что Deployment Target корректен:

    Установите Deployment Target на macOS 10.9 (или iOS 7). Это можно сделать в том же разделе Build Settings → Deployment → macOS Deployment Target.

  3. Используйте Swift 5 (или ниже):

    Swift 5 гарантирует стабильность ABI (Application Binary Interface) начиная с macOS 10.14.4 и iOS 12.2. Для более старых систем Swift 5 также работает, но только при встроенном runtime. Swift 4.2 и более ранние версии также требуют встраивания runtime.

  4. Проверьте совместимость с API:

    Даже если Swift runtime будет встроен, вы не сможете использовать API, которые появились в более новых версиях macOS/iOS. Например, методы из Foundation или AppKit, доступные только с macOS 10.10+, вызовут ошибку на 10.9. Используйте @available для проверки версии:

    if #available(macOS 10.10, *) {
        // Используем новый API
    } else {
        // Fallback для 10.9
    }

Проверка после сборки

После того как вы включите Always Embed Swift Standard Libraries, соберите приложение. Откройте .app пакет (ПКМ → «Показать содержимое пакета») и проверьте папку Frameworks. Там должны быть файлы вида libswiftCore.dylib, libswiftFoundation.dylib и другие. Если они есть — всё сделано правильно.

Важное замечание

Встраивание Swift runtime увеличивает размер приложения примерно на 10–15 МБ. Также Apple официально не рекомендует поддерживать системы старше macOS 10.14.4 / iOS 12.2, так как на них не выходят обновления безопасности. Однако для образовательных целей или legacy-проектов это вполне рабочий вариант.

<<>>

Альтернативный подход: статическая линковка Swift runtime

Вместо динамического встраивания runtime (как описано в основном ответе), вы можете попробовать статическую линковку Swift-библиотек. В этом случае код runtime компилируется прямо в исполняемый файл вашего приложения. Это полностью устраняет зависимость от внешних .dylib-файлов.

Как это сделать:

  1. В Build Settings найдите параметр Swift Compiler - Code Generation.
  2. Установите Embed Swift Runtime Libraries в No (это отключает динамическое встраивание).
  3. Далее найдите Other Linker Flags и добавьте флаг -static-stdlib (для macOS) или -static-swift-stdlib (для iOS).

После этого при сборке компилятор включит весь необходимый Swift runtime прямо в ваш бинарный файл. Размер приложения может немного увеличиться, но зато исчезнут проблемы с загрузкой библиотек на старых системах.

Минусы статической линковки:

  • Увеличивается время компиляции.
  • Размер исполняемого файла может быть больше, чем при динамическом встраивании.
  • Не все сторонние Swift-фреймворки корректно работают со статической линковкой — могут потребоваться дополнительные настройки.

Статическая линковка — более «чистый» способ с точки зрения распространения приложения, но требует больше тестирования. Для простых проектов или учебных целей рекомендую сначала попробовать динамическое встраивание через Always Embed Swift Standard Libraries, так как это проще и надёжнее.