Разрешение циклических ссылок 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)!
    }
}
Другие вопросы по тегам