SwiftMiddleTechnical

Как Swift взаимодействует с Objective-C?

Swift и Objective-C взаимодействуют через bridging header (ObjC → Swift) и автогенерируемый ModuleName-Swift.h (Swift → ObjC). Swift-классы должны наследоваться от NSObject и быть помечены @objc, чтобы стать видимыми из ObjC.

Swift и Objective-C: взаимодействие

Swift и Objective-C могут сосуществовать в одном проекте благодаря специальному bridging-слою, который Xcode и компилятор генерируют автоматически. Это позволяет постепенно мигрировать ObjC-кодовые базы на Swift без переписывания с нуля.

Использование Objective-C из Swift

В app target создаётся bridging header: ModuleName-Bridging-Header.h. Любой #import в нём делает соответствующие ObjC-классы и функции видимыми в Swift.

// MyApp-Bridging-Header.h
#import "LegacyParser.h"
#import <SomeObjCLibrary/SomeObjCLibrary.h>
// Swift-файл
let parser = LegacyParser()
parser.parse("input")  // вызов ObjC-метода из Swift

Для фреймворков и SPM-пакетов bridging header недоступен — там используют module map: файл module.modulemap, определяющий ObjC-модуль, который Swift может импортировать напрямую через import ModuleName.

Использование Swift из Objective-C

Компилятор автоматически генерирует заголовок ModuleName-Swift.h. Чтобы класс или метод попал в этот заголовок, необходимо:

  • Класс должен наследоваться от NSObject (или быть @objc с ограничениями).
  • Метод/свойство должны быть помечены @objc явно или неявно (через @objcMembers).
  • Должны использоваться только типы, совместимые с ObjC (нет generics, нет enums с associated values).
// Swift
@objc class UserManager: NSObject {
    @objc var currentUser: String = ""

    @objc func login(username: String, completion: @escaping (Bool) -> Void) {
        // ...
        completion(true)
    }
}
// Objective-C
#import "MyApp-Swift.h"

UserManager *manager = [[UserManager alloc] init];
[manager loginWithUsername:@"alice" completion:^(BOOL success) {
    NSLog(@"Login: %d", success);
}];

Маппинг типов

  • StringNSString — автоматический bridge, без копирования.
  • Array<T>NSArray, DictionaryNSDictionary, SetNSSet.
  • Int, Double, BoolNSNumber через as cast.
  • Swift Optional → ObjC nullable pointer; String?NSString * _Nullable.
  • Swift enums без associated values и с @objc → ObjC enum (Int raw value).

Nullability аннотации в ObjC для Swift

Чтобы Swift не импортировал все ObjC-указатели как ImplicitlyUnwrappedOptional, добавляйте аннотации в ObjC-заголовках:

// ObjC (LegacyParser.h)
NS_ASSUME_NONNULL_BEGIN
@interface LegacyParser : NSObject
- (nullable NSString *)parse:(NSString *)input error:(NSError **)error;
@end
NS_ASSUME_NONNULL_END

@objc(name) для переименования

@objc(RWUserSession)
class UserSession: NSObject {
    @objc(startWithToken:)
    func start(token: String) { }
}

Подводные камни

  • Generics не экспортируются в ObjC — Swift generic classes и methods невидимы в Objective-C; нужно создавать non-generic обёртки.
  • Swift-only типы ломают interop — struct, enum с associated values, protocol with associated types, actor — всё это не может быть представлено в ObjC.
  • Циклические импорты — ObjC-файл импортирует Swift-заголовок, а Swift-файл через bridging header импортирует тот же ObjC-файл → ошибка компиляции. Решение: forward declaration в ObjC.
  • Производительность bridging коллекций — конвертация Array<String> в NSArray при каждом вызове — O(n) копирование; критично в tight loops.
  • @objcMembers захватывает всё — аннотация делает публичным весь класс, включая методы, которые вы не планировали expose-ить в ObjC; предпочитайте явные @objc на конкретных членах.
  • Исключения ObjC не ловятся в Swift — ObjC @throw минует Swift try/catch; нужен ObjC-враппер с NS_ERROR_ENUM или tryBlock.
  • Изменение сигнатуры ломает ObjC-вызывающих — переименование Swift-параметра меняет ObjC selector; используйте @objc(newName:) для обратной совместимости.

Common mistakes

  • Сводить «Swift взаимодействует с Objective-C» к синтаксису и не объяснять модель памяти.
  • Игнорировать жизненный цикл, основной поток или момент освобождения ресурсов в сценарии swift-29.
  • Выбирать API по привычке, не проверяя состояние, ошибки, доступность и платформенные ограничения.

What the interviewer is testing

  • Формулирует точную модель для «Swift взаимодействует с Objective-C» и подтверждает ее корректным примером.
  • Умеет связать ответ с система типов, тестированием и отладкой на устройстве.
  • Называет ограничения подхода swift-29, включая производительность, память и сопровождение.

Sources

Related topics