Avatar ·

iOS приложение с фреймворком падает на устройстве: dyld: Library not loaded, Xcode 6 Beta

Всем привет! Я начинающий iOS разработчик, перехожу на Swift и Xcode 6 Beta. Создал свой первый фреймворк для общего кода между приложением и расширением (Today Widget). Всё отлично работает в симуляторе, но когда я запускаю на реальном устройстве (iPhone 5s, iOS 8 beta), приложение падает сразу после запуска с ошибкой: ``` dyld: Library not loaded: @rpath/MyFramework.framework/MyFramework Referenced from: /private/var/containers/Bundle/Application/.../MyApp.app/MyApp Reason: image not found ``` Вот как я настроил проект: - В основном таргете (MyApp) я добавил фреймворк в раздел "Linked Frameworks and Libraries". - В Build Settings для таргета MyApp я указал "Embedded Content Contains Swift Code" = YES. - Фреймворк лежит в той же рабочей области, ссылка на него добавлена. Код простой — в фреймворке есть класс `Greeter`: ```swift // MyFramework/Greeter.swift import Foundation public class Greeter { public func greet(name: String) -> String { return "Hello, \(name)!" } } ``` И в приложении я его использую: ```swift // ViewController.swift import UIKit import MyFramework class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let greeter = Greeter() print(greeter.greet(name: "World")) } } ``` Что я делаю не так? Почему на устройстве не подгружается библиотека, хотя в симуляторе всё работает? Пробовал чистить проект, перезапускать Xcode — не помогает. Заранее спасибо за помощь! <<>>

Причина проблемы

Ваша ошибка — классическая проблема с динамическими библиотеками в iOS, особенно остро проявившаяся в Xcode 6 Beta из-за изменений в работе Swift runtime. Дело в том, что Xcode 6 Beta автоматически не добавляет ваш фреймворк в Embedded Binaries (встроенные бинарники) приложения. В симуляторе система находит библиотеку благодаря общим путям поиска, но на реальном устройстве приложение запускается в изолированной песочнице, где фреймворк физически отсутствует — отсюда и dyld: Library not loaded.

Ключевой момент: Linked Frameworks and Libraries (связывание) — это только указание линковщику, что ваш код зависит от фреймворка. Но чтобы фреймворк попал на устройство, его нужно встроить (embed) в пакет приложения. В Xcode 6 Beta этот шаг не автоматизирован для пользовательских фреймворков.

Решение

Вам нужно явно добавить фреймворк в Embedded Binaries вашего основного таргета. Сделайте следующее:

  1. В Project Navigator выберите ваш проект (синяя иконка).
  2. Выберите таргет MyApp (ваше основное приложение).
  3. Перейдите на вкладку General.
  4. Прокрутите вниз до раздела Embedded Binaries.
  5. Нажмите на плюс (+) и выберите MyFramework.framework из списка.

После этого Xcode скопирует фреймворк в папку Frameworks внутри вашего .app пакета. Теперь при запуске на устройстве dyld сможет найти библиотеку по пути @rpath/MyFramework.framework/MyFramework.

Дополнительные проверки

  • Build Phases → Embed Frameworks: Убедитесь, что в вашем таргете есть фаза сборки Embed Frameworks (Xcode 6 Beta иногда не создаёт её автоматически). Если её нет — добавьте вручную через Editor → Add Build Phase → Add Embed Frameworks Build Phase и укажите ваш фреймворк.
  • Runpath Search Paths: В Build Settings вашего таргета проверьте Runpath Search Paths. Для динамических фреймворков значение должно быть @executable_path/Frameworks (или @loader_path/Frameworks для расширений). Xcode обычно устанавливает это автоматически, но на всякий случай проверьте.
  • Clean Build Folder: После изменения настроек обязательно сделайте Product → Clean Build Folder (зажмите Option), затем пересоберите проект.

Полный рабочий пример

После всех исправлений ваш проект должен выглядеть так в настройках таргета MyApp:

General:
  - Linked Frameworks and Libraries: MyFramework.framework (Required)
  - Embedded Binaries: MyFramework.framework

Build Settings:
  - Runpath Search Paths: @executable_path/Frameworks

Теперь при сборке на устройство фреймворк будет скопирован в MyApp.app/Frameworks/MyFramework.framework, и dyld успешно загрузит его при запуске.

Если проблема сохраняется — проверьте, что ваш фреймворк собран как динамическая библиотека (Mach-O Type = Dynamic Library), а не статическая. В Xcode 6 Beta для Swift-фреймворков это стандартное поведение.

<<>>

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

Если вы не хотите заморачиваться с настройками Embedded Binaries, есть два обходных пути:

1. Превратить фреймворк в статическую библиотеку

В Xcode 6 Beta Swift-фреймворки по умолчанию динамические. Вы можете изменить Mach-O Type на Static Library в Build Settings вашего фреймворка. Тогда код скомпилируется прямо в исполняемый файл приложения, и проблема с dyld исчезнет. Минус — увеличится размер бинарника, и вы не сможете использовать фреймворк для расширений (Today Widget, Share Extension), так как они требуют динамической загрузки.

2. Добавить скрипт в Build Phases

Если Xcode 6 Beta упорно не хочет встраивать фреймворк, добавьте в Build Phases таргета приложения новый Run Script с таким кодом:

# Встраиваем фреймворк вручную
FRAMEWORK_NAME="MyFramework"
FRAMEWORK_PATH="${BUILT_PRODUCTS_DIR}/${FRAMEWORK_NAME}.framework"
DESTINATION="${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}"

mkdir -p "$DESTINATION"
cp -R "$FRAMEWORK_PATH" "$DESTINATION"

Этот скрипт скопирует фреймворк в папку Frameworks внутри .app после каждой сборки. Он менее элегантен, но работает, если стандартные методы подводят.

Рекомендую всё же разобраться с Embedded Binaries — это правильный способ для Xcode 6 Beta и всех последующих версий.