Avatar ·

Не удаётся использовать классы Swift внутри Objective-C в статической библиотеке

Всем привет! Я новичок в iOS-разработке и пытаюсь интегрировать Swift-код в существующий проект на Objective-C. У меня есть статическая библиотека (static library), написанная на Swift, и я хочу использовать её классы в основном Objective-C приложении. Вот пример моего Swift-класса: ```swift import Foundation @objc public class MySwiftClass: NSObject { @objc public func sayHello() -> String { return "Hello from Swift!" } @objc public var name: String = "" } ``` Я добавил этот файл в проект, настроил bridging header, но когда пытаюсь импортировать Swift-класс в Objective-C файл, получаю ошибку: "No visible @interface for 'MySwiftClass' declares the selector 'sayHello'". При этом в bridging header я написал `#import "ProductModuleName-Swift.h"`, но Xcode не видит мой класс. Подскажите, пожалуйста, что я делаю не так? Нужно ли как-то по-особенному настраивать статическую библиотеку для работы с Objective-C? Может быть, есть какие-то флаги компиляции или настройки в Build Settings, которые я пропустил? Буду очень благодарен за помощь! P.S. Использую Xcode 14, Swift 5, Objective-C проект с поддержкой iOS 15+. Заранее спасибо! <<>>

Почему возникает проблема

Основная причина — статическая библиотека на Swift не генерирует автоматически заголовочный файл совместимости для Objective-C (ProductModuleName-Swift.h), если не настроена правильно. Swift-классы должны быть явно помечены @objc и наследоваться от NSObject (что вы сделали верно), но для статической библиотеки требуется дополнительная конфигурация.

Пошаговое решение

Вот что нужно сделать, чтобы Swift-классы стали доступны из Objective-C в статической библиотеке:

1. Настройка сборки библиотеки

В проекте вашей статической библиотеки перейдите в Build Settings и установите:

  • Defines Module — Yes
  • Product Module Name — задайте имя модуля (например, MyLibrary)
  • Install Objective-C Compatibility Header — Yes
  • Objective-C Generated Interface Header Name — оставьте по умолчанию ($(PRODUCT_MODULE_NAME)-Swift.h)

2. Маркировка классов

Убедитесь, что все публичные классы и методы, которые вы хотите использовать из Objective-C, помечены @objc и наследуются от NSObject. Ваш пример уже корректен, но для надёжности добавьте @objcMembers к классу:

import Foundation

@objcMembers public class MySwiftClass: NSObject {
    public func sayHello() -> String {
        return "Hello from Swift!"
    }
    
    public var name: String = ""
}

3. Импорт в Objective-C

В Objective-C файле импортируйте сгенерированный заголовок:

#import "MyLibrary-Swift.h"

@implementation MyViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    MySwiftClass *swiftObject = [[MySwiftClass alloc] init];
    swiftObject.name = @"Test";
    NSLog(@"%@", [swiftObject sayHello]);
}
@end

4. Проверка флагов линковки

В главном проекте (не в библиотеке) в Build Settings добавьте в Other Linker Flags:

  • -ObjC — загружает все Objective-C классы из статических библиотек
  • -all_load (если -ObjC не помогает) — загружает все объектные файлы

5. Дополнительная проверка

Если всё ещё не работает, проверьте:

  • Что ваша библиотека собрана как Static Library (не Dynamic Framework)
  • Что в Build Phases -> Headers ваши Swift-файлы отмечены как Public
  • Очистите проект (Cmd+Shift+K) и пересоберите

Пример полной настройки

Вот минимальный рабочий пример. Swift-файл библиотеки:

// MyClass.swift
import Foundation

@objcMembers public class MyClass: NSObject {
    public func greet() -> String {
        return "Привет из Swift!"
    }
}

Objective-C код в основном проекте:

#import "MyLibrary-Swift.h"

@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    MyClass *obj = [[MyClass alloc] init];
    NSLog(@"%@", [obj greet]);
    return YES;
}
@end

После правильной настройки статическая библиотека сгенерирует файл MyLibrary-Swift.h, и все @objc-классы будут доступны в Objective-C.

<<>>

Альтернативный подход: использование модулей (Modules)

Если статическая библиотека продолжает создавать проблемы, рассмотрите возможность преобразования её в динамический фреймворк (Dynamic Framework). Это упрощает интеграцию Swift и Objective-C:

  1. В настройках библиотеки измените Mach-O Type на Dynamic Library
  2. В главном проекте добавьте фреймворк в Embedded Binaries
  3. Импортируйте модуль: @import MyLibrary; (вместо #import)

Преимущества:

  • Автоматическая генерация модульного заголовка
  • Не нужно вручную настраивать флаги линковки
  • Лучшая поддержка Swift-фич (например, extension-ов)

Недостаток: динамические фреймворки увеличивают размер приложения и время запуска, поэтому для небольших проектов статическая библиотека предпочтительнее. Но для быстрого решения проблемы — это надёжный вариант.

Также проверьте, не конфликтуют ли ваши Swift-классы с именами Objective-C классов. Иногда Xcode не генерирует заголовок, если есть дублирование имён.