是否可以在Obj-C中使用Swift的枚举?


144

我正在尝试将我的一些Obj-C类转换为Swift。还有其他一些Obj-C类仍在该转换后的类中使用枚举。我在“预发布文档”中进行搜索,但找不到它,或者我错过了它。有没有办法在Obj-C类中使用Swift枚举?或指向此问题的文档的链接?

这就是我在旧的Obj-C代码和新的Swift代码中声明枚举的方式。

我以前的Obj-C代码:

typedef NS_ENUM(NSInteger, SomeEnum)
{
    SomeEnumA,
    SomeEnumB,
    SomeEnumC
};

@interface SomeClass : NSObject

...

@end

我的新Swift代码:

enum SomeEnum: NSInteger
{
    case A
    case B
    case C
};

class SomeClass: NSObject
{
    ...
}

更新:从答案。在Swift低于1.2的旧版本中无法完成。但是根据这个官方的Swift Blog。在与XCode 6.3一起发布的Swift 1.2中,您可以在Objective-C中使用Swift Enum,方法是@objcenum


确实不需要更改现有代码。有关Swift和Objective-C之间的交互,请观看WWDC视频。
gnasher729 2014年

我只是想检查我的项目是否仍然可以正常工作,如果将来我的项目中将有一个快速班级,但是我不知道应该添加哪个班级来对其进行测试。因此,我改用旧的。无论如何,谢谢您的帮助。
myLifeasdog 2014年

Answers:


226

从Swift版本1.2(Xcode 6.3)开始,您可以。只需在枚举声明前面加上前缀@objc

@objc enum Bear: Int {
    case Black, Grizzly, Polar
}

无耻地从Swift博客中获取

注意:这不适用于String枚举或具有关联值的枚举。您的枚举必须是整数绑定的


在Objective-C中,这看起来像

Bear type = BearBlack;
switch (type) {
    case BearBlack:
    case BearGrizzly:
    case BearPolar:
       [self runLikeHell];
}

8
非常感谢您指出这一点...请注意,尽管在目标C中枚举值将被调用BearBlackBearGrizzly并且BearPolar
nburk 2015年

1
那有意义吗?尤其是当您查看它如何从obj-c转换为swift .. @nburk
Daniel Galasko 2015年

1
是的,这可行。但是,至少在我的情况下,必须在枚举中添加“公共”属性,以便在项目的Objective-C侧可以访问它,例如:“ @ objc public enum Bear:Int”
Pirkka Esko

太糟糕了,我没有看到任何证据表明Swift枚举相关的值是可能的。一厢情愿
finneycanhelp 2015年

2
@AJit为什么要这么做?只需将枚举添加到其自己的标头中,然后将其导入到桥接标头中,否则它是Swift专有的
Daniel Galasko 2015年

31

要扩展所选答案...

使用可以在Swift和Objective-C之间共享Swift样式枚举NS_ENUM()

它们只需要在Objective-C上下文中使用定义,NS_ENUM()并且可以使用Swift点表示法来使用。

从将Swift与Cocoa和Objective-C结合使用

Swift会将带有该NS_ENUM宏标记的所有C样式枚举作为Swift枚举导入。这意味着枚举值名称的前缀在导入到Swift中时会被截断,无论它们是在系统框架中定义还是在自定义代码中定义。

目标C

typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
   UITableViewCellStyleDefault,
   UITableViewCellStyleValue1,
   UITableViewCellStyleValue2,
   UITableViewCellStyleSubtitle
};

迅速

let cellStyle: UITableViewCellStyle = .Default

我在UITableViewCellStyle中看到“此处不允许使用函数定义”,我在做什么错?当然,我有不同的名称,而不是UITableViewCellStyle。
Cristi Băluță 2014年

1
正如加拉斯科(Galasko)先生在下面的回答中所指出的那样,Swift 1.2允许在Swift中定义枚举并在Obj-c中使用。这种定义样式,即NS_ENUM,仍然可以在Obj-c中使用,但是从Swift版本1.2开始,您可以使用任何一个选项。
SirNod

我发现Swift中的ObjC枚举存在问题:它们不是失败的。在类似if let a = MyEnum(rawValue: 12345)12345不是该枚举的一部分的片段中,结果不是可选的,而是一些无效的枚举。
生物

30

从“ 将Swift与Cocoa和Objective-C结合使用”指南中:

Swift类或协议必须使用@objc属性标记,才能在Objective-C中访问和使用。[...]

您可以访问标有@objc属性的类或协议中的任何内容,只要它们与Objective-C兼容即可。这不包括仅Swift的功能,例如此处列出的功能:

在Swift中定义的泛型元组/ 枚举 / 在Swift中定义的结构/ 在Swift中定义的顶级函数/在Swift中定义的全局变量/在Swift中定义的Typealiases /在Swift型变元/嵌套类型/ Curried函数中

因此,不,您不能在Objective-C类中使用Swift枚举。


2
有解决方法吗?我的意思是,如果我创建一个Swift类并且我绝对需要一个枚举。我如何使该枚举也可用于Objective-C?
劳尔·洛佩兹

4
@RaulLopezVillalpando如果您知道要与Objective-C互操作,则应该在Objective-C中声明枚举并让两种语言共享。
格雷戈里·希格利

3
“是的,所以我们架起了这座桥来帮助您过渡到Swift,但是如果您想使用任何很酷的东西(例如枚举,结构,泛型...这样的话,那就没用了……)
Kevin R

22
这个答案不再有效!!从Xcode 6.3 / Swift 1.2开始,Swift枚举也可以在Objective-c中使用,@objc就像@DanielGalasko在下面的答案中指出的那样!
nburk 2015年

9
为了澄清以上注释,引用了Swift 2.1以后文档中的当前文本“在Swift中定义的枚举,没有Int原始值类型 ”。因此,如果您在Swift中的枚举声明为Int原始值类型,@obj enum MyEnum: Int则如前所述,它将在Objective-C文件上正常工作。如果您的枚举使用其他原始值类型(如)声明@obj enum MyOtherEnum: String,则将无法在Objective-C文件上使用它
jjramos

7

Swift 4.1,Xcode 9.4.1:

1)Swift枚举必须以前缀@objcInt输入:

// in .swift file:
@objc enum CalendarPermission: Int {
    case authorized
    case denied
    case restricted
    case undetermined
}

2)Objective-C名称是枚举名称+案例名称,例如CalendarPermissionAuthorized

// in .m file:
// point to something that returns the enum type (`CalendarPermission` here)
CalendarPermission calPermission = ...;

// use the enum values with their adjusted names
switch (calPermission) {
    case CalendarPermissionAuthorized:
    {
        // code here
        break;
    }
    case CalendarPermissionDenied:
    case CalendarPermissionRestricted:
    {
        // code here
        break;
    }
    case CalendarPermissionUndetermined:
    {
        // code here
        break;
    }
}

并且,当然,请记住将您的Swift桥接标头作为Objective-C文件的导入列表中的最后一项导入:

#import "MyAppViewController.h"
#import "MyApp-Swift.h"

为什么MyApp-Swift应该是最后一个?
Paul T.

@PaulT。:可能与处理顺序有关。尝试将其放在其他位置,您将发现它将无法工作。
leanne

我在当前项目中检查了几乎所有文件都在导入部分的末尾,但是在几个文件中却没有在末尾并且项目可以工作。可能在新的Xcode中有效吗?我现在无法检查,因为我当前的项目需要花很多时间才能编译:),但我稍后要检查
Paul T.

2

如果您希望按原样保留ObjC代码,则可以在项目中添加帮助程序头文件:

Swift2Objc_Helper.h

在头文件中添加以下枚举类型:

typedef NS_ENUM(NSInteger, SomeEnum4ObjC)
{
   SomeEnumA,
   SomeEnumB
};

您的.m文件中可能还有其他地方需要更改:包括隐藏的头文件:

#import "[YourProjectName]-Swift.h"

用您的项目名称替换[YourProjectName]。该头文件公开了所有Swift定义的@objc类,它们是ObjC的枚举。

您可能会收到有关从枚举类型进行隐式转换的警告消息...可以。

顺便说一句,您可以使用此标头帮助程序文件保留一些ObjC代码,例如#define常量。


0

如果您(像我一样)真的想使用String枚举,则可以为Objective-C创建一个专门的接口。例如:

enum Icon: String {
    case HelpIcon
    case StarIcon
    ...
}

// Make use of string enum when available:
public func addIcon(icon: Icon) {
    ...
}

// Fall back on strings when string enum not available (objective-c):
public func addIcon(iconName:String) {
    addIcon(Icon(rawValue: iconName))
}

当然,这不会给您带来自动完成的便利(除非您在Objective-C环境中定义其他常量)。


0

这可能会有所帮助

问题陈述:-我在swift类中有枚举,正在从其他swift类访问它,现在我需要从我的目标C类之一访问它。

从Objective-C类访问它之前:

enum NTCType   {
    case RETRYNOW
    case RETRYAFTER
}
 var viewType: NTCType? 

从目标C类访问它的更改

@objc  enum NTCType :Int  {
    case RETRYNOW
    case RETRYAFTER
}

并添加一个函数以将其传递给值

  @objc  func setNtc(view:NTCType)  {
        self.viewType = view; // assign value to the variable
    }

0

经过研究之后,我一直只找到部分答案,因此我创建了一个与Objective C桥接的Swift应用程序的完整示例,其中包含Objective C代码使用的Swift枚举和Swift代码使用的Objective C枚举。这是一个可以运行和试验的简单Xcode项目。它是使用Xcode 10.3和Swift 5.0编写的

示例项目


我不明白,你的项目使用的目的C.同样迅速枚举的定义迅速枚举enum SwAnimal缺乏龙头@obj
oliolioli

0

如果您试图观察一个如下所示的枚举:

enum EnumName: String {
    case one = "One"
    case two = "Two"
}

这个解决方法对我有所帮助。

可观察类:

  • 创造 @objc dynamic var observable: String?
  • 创建您的枚举实例,如下所示:

    private var _enumName: EnumName? {
        didSet {
            observable = _enumName!.rawValue
        }
    }

观察员类别:

  • 创造 private var _enumName: EnumName?
  • 创造 private let _instance = ObservableClass()
  • 创造

    private var _enumObserver: NSKeyValueObservation = _instance.observe(\.observable, options: .new, changeHandler: { [weak self] (_, value) in
        guard let newValue = value.newValue else { return }
        self?._enumName = EnumName(rawValue: period)!
    })

比它。现在,每次_enumName在observable类中更改时,observer类上的相应实例也将立即更新。

当然,这是一个过于简化的实现,但是它应该使您了解如何观察KVO不兼容的属性。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.