Avatar ·

Ошибка "No such module" в Xcode: фреймворк есть, но не импортируется

Я новичок в iOS-разработке и столкнулся со странной проблемой. У меня есть проект на Swift, я добавил в него фреймворк (например, Alamofire или Firebase) через CocoaPods, SPM или просто вручную. Файл .framework лежит в папке проекта, в настройках Build Phases -> Link Binary With Libraries он отображается, путь к нему указан в Framework Search Paths. Но когда я пишу `import Alamofire` в своём .swift файле, Xcode выдаёт ошибку: "No such module 'Alamofire'". Я пробовал: - Очищать проект (Product -> Clean Build Folder) - Удалять DerivedData - Перезапускать Xcode и перезагружать компьютер - Проверять, что фреймворк действительно добавлен в таргет (Build Phases) - Проверять, что фреймворк скомпилирован для правильной архитектуры (arm64, x86_64) Всё равно ошибка остаётся. При этом в Objective-C файлах импорт через `#import` работает, а в Swift — нет. Проект не использует мост (bridging header). Как это исправить? Подскажите, пожалуйста, что я делаю не так. Пример кода: import UIKit import Alamofire // Ошибка: No such module 'Alamofire' class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() AF.request("https://example.com").response { response in print(response) } } } Xcode версии 15.2, проект для iOS 17. <<>>

Причина ошибки и базовое решение

Ошибка "No such module" в Swift почти всегда связана с тем, что Xcode не видит модульные карты (module.modulemap) вашего фреймворка. Swift работает не с заголовочными файлами, как Objective-C, а с модулями. Даже если фреймворк физически присутствует в проекте, Swift не сможет его импортировать, если модуль не объявлен корректно.

Вот пошаговый план, который решает 90% таких проблем:

Шаг 1. Проверьте, что фреймворк поддерживает Swift

Некоторые старые или самописные фреймворки написаны только на Objective-C и не имеют модульной карты. Чтобы использовать их в Swift, нужно либо создать bridging header, либо вручную добавить файл module.modulemap.

Шаг 2. Настройка Build Settings

Убедитесь, что в настройках вашего таргета:

  • Defines Module — YES (для вашего основного модуля)
  • Module Map File — путь к файлу module.modulemap, если он нестандартный
  • Framework Search Paths — содержит путь к папке, где лежит .framework
  • Allow Non-Modular Includes In Framework Modules — YES (иногда помогает, если фреймворк не совсем "чистый")

Шаг 3. Для CocoaPods: переустановка и workspace

Если вы используете CocoaPods:

pod deintegrate
pod install --clean-install

Всегда открывайте .xcworkspace, а не .xcodeproj. Убедитесь, что модуль добавлен в ваш Podfile:

target 'YourApp' do
  pod 'Alamofire'
end

Шаг 4. Для Swift Package Manager (SPM)

Если фреймворк добавлен через SPM:

  • File → Add Packages → убедитесь, что пакет добавлен для вашего таргета
  • Проверьте в General → Frameworks, Libraries, and Embedded Content — библиотека должна быть там
  • Иногда помогает: File → Packages → Reset Package Caches

Шаг 5. Для ручного добавления .framework

Создайте файл module.modulemap внутри папки фреймворка:

framework module MyFramework {
  umbrella header "MyFramework.h"
  export *
  module * { export * }
}

Затем укажите путь к нему в Build Settings → Module Map File.

Шаг 6. Чистка и пересборка

После всех изменений обязательно выполните:

Product → Clean Build Folder (Option + Shift + Cmd + K)
Delete DerivedData (File → Workspace Settings → DerivedData → Open, удалите папку)

Шаг 7. Проверка архитектуры

Убедитесь, что фреймворк собран для архитектуры вашего симулятора/устройства. Для отладки на симуляторе нужна x86_64 или arm64 (для Apple Silicon). Используйте команду в терминале:

lipo -info /path/to/MyFramework.framework/MyFramework

Пример рабочей конфигурации (Alamofire через SPM)

Вот как должен выглядеть рабочий проект:

// Package Dependencies в Xcode:
// https://github.com/Alamofire/Alamofire.git, версия 5.8.0

// Ваш файл:
import UIKit
import Alamofire // ✅ теперь работает

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        print("Alamofire version: \(AF.version)")
    }
}

Если после всех шагов ошибка остаётся — проверьте, не конфликтует ли ваш проект с другими таргетами (например, тестами). Иногда нужно добавить фреймворк отдельно для тестового таргета в Build Phases.

<<>>

Альтернативный подход: использование bridging header

Если фреймворк написан на Objective-C и не предоставляет модульной карты, самый простой способ — создать bridging header и импортировать его вручную:

  1. Создайте новый файл Objective-C (.m) в проекте — Xcode предложит создать bridging header. Согласитесь.
  2. В полученном файле YourProject-Bridging-Header.h напишите:
#import "MyFramework/MyFramework.h"

После этого все публичные классы и функции фреймворка будут доступны в Swift без import.

Важно: Этот метод не подходит для Swift-фреймворков и не даёт доступа к Swift-опциональным типам (например, Result). Но для Objective-C библиотек это надёжное решение, которое не требует настройки модулей.

Ещё один частый случай — фреймворк лежит в нестандартной папке. Проверьте, что в Build Settings → Framework Search Paths путь указан рекурсивно (recursive), особенно если фреймворк находится внутри подпапок.