Разрешение циклических ссылок Swift.h и Bridging-Header.h с использованием перечислений
У меня есть заголовок Objective-C, который должен использоваться классом Swift. Тем не менее, этот заголовок должен использовать Swift.h
файл для перечисления, объявленного в файле Swift. Другими словами, установка выглядит следующим образом:
MPViewController.h
#import "MyProject-Swift.h"
@interface MPViewController: UIViewController
@property (nonatomic, assign) MPSomeEnum theEnum;
...
@end
MyProject-Bridging-header.h
...
#import "MPViewController.h"
...
SomeEnum.swift
@objc enum MPSomeEnum: Int {
...
}
При компиляции кода я получаю три ошибки:
- Файл "MyProject-Swift.h" не найден
- Не удалось выдать предварительно скомпилированный заголовок
[Xcode DerivedData folder]/[...]/MyProject-Bridging-Header-swift_[...].pch
для мостового заголовка[Project folder]/MyProject-Bridging-Header.h
- Неизвестное имя типа 'MPSomeEnum'
Правильно ли я предположить, что это вытекает из круговой ссылки между MyProject-Swift.h
и соединительный заголовок MyProject-Bridging-Header.h
? Если посмотреть на аналогичный вопрос, то одним из решений является использование предварительного объявления. Тем не менее, кажется невозможным заранее объявить перечисление, поэтому, возможно, единственный способ сделать это - перенести определение перечисления в файл Objective-C вообще?
1 ответ
TL&DR; Как вы и подозревали, вам нужно либо переместить объявление enum в Objective-C, либо перенести класс в Swift.
Предварительные объявления перечислений возможны в Objective-C:
@property SomeEnum someProperty;
- (void)doSomethingWithEnum:(enum SomeEnum)enumValue;
Однако правильные перечисления Какао являются typedefs для NSInteger
: typedef NS_ENUM(NSInteger, MyEnum)
и enum
Ключевое слово не содержит достаточно информации о том, сколько места нужно выделить при его использовании, поэтому вы будете сталкиваться со всеми видами ошибок компилятора, когда захотите использовать такие объявления. Таким образом, перечисление объявлено в Swift
не может быть объявлен в Objective-C.
Теперь, если вы действительно хотите сохранить определение перечисления в Swift, вы можете использовать обходной путь и объявить его как NSInteger
в Objective-C, при этом предоставляя специализированное свойство в Swift:
// NS_REFINED_FOR_SWIFT imports this in Swift as __theEnum
@property(nonatomic, assign) NSInteger theEnum NS_REFINED_FOR_SWIFT;
extension MPViewController {
// we provide a wrapper around the Objective-C property
var theEnum: MPSomeEnum {
// this uses a forced unwrap, beware :)
return MPSomeEnum(rawValue: theEnum)!
}
}