解析涉及枚举的 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"
...

有些.swift

@objc enum MPSomeEnum: Int {
    ...
}

编译代码时,我收到三个错误:

  • 找不到"MyProject-Swift.h"文件
  • 无法发出用于桥接标头[Project folder]/MyProject-Bridging-Header.h的预编译标头[Xcode DerivedData folder]/[...]/MyProject-Bridging-Header-swift_[...].pch
  • 未知类型名称"MPSomeEnum">

我是否正确假设这源于MyProject-Swift.h和桥接标头MyProject-Bridging-Header.h之间的循环引用?从类似的问题来看,一个解决方案是使用前向声明。但是,似乎不可能转发声明枚举,所以也许唯一的方法是将枚举定义完全移动到 Objective-C 文件中?

TL&DR; 正如你所怀疑的,你需要将枚举声明移动到 Objective-C,或者将类迁移到 Swift。

枚举的前向声明可以在 Objective-C 中实现:

@property SomeEnum someProperty;
- (void)doSomethingWithEnum:(enum SomeEnum)enumValue;

然而,正确的Cocoa枚举是typedefs NSIntegertypedef NS_ENUM(NSInteger, MyEnum),并且enum关键字没有足够的信息来分配多少空间,所以当你想使用这样的声明时,你会陷入所有类型的编译器错误。因此,在 Swift 中声明的枚举在 Objective-C 中不可向前声明。

现在,如果你真的想在 Swift 中保留枚举定义,你可以使用一种解决方法,并在 Objective-C 中将其声明为 NSInteger,同时在 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)!
    }
}

最新更新