【问题标题】:Is it possible to use Swift's Enum in Obj-C?是否可以在 Obj-C 中使用 Swift 的枚举?
【发布时间】:2014-07-31 02:49:00
【问题描述】:

我正在尝试将我的一些 Obj-C 类转换为 Swift。其他一些 Obj-C 类仍在该转换后的类中使用枚举。我在 Pre-Release Docs 中搜索并找不到它,或者我错过了它。有没有办法在 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 中,您可以通过在 enum 前面添加 @objc 在 Objective-C 中使用 Swift Enum

【问题讨论】:

  • 实际上不需要更改现有代码。有关 Swift 和 Objective-C 之间的交互,请观看 WWDC 视频。
  • 我只是想检查我的项目是否仍然有效,如果将来我的项目中会有一个 swift 类,但我不知道我应该添加什么类来测试它。所以,我改用旧的。无论如何,谢谢你的帮助。

标签: objective-c enums swift


【解决方案1】:

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

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

无耻取自Swift Blog

注意:这不适用于字符串枚举或具有关联值的枚举。您的枚举需要是 Int-bound


在 Objective-C 中,这看起来像

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

【讨论】:

  • 非常感谢您指出...请注意,在objective-c中,尽管枚举值将被称为BearBlackBearGrizzlyBearPolar
  • 这有道理,不是吗?尤其是当您查看它是如何从 obj-c 转换为 swift 时.. @nburk
  • 是的,这行得通。但是,至少在我的情况下,必须将“公共”属性添加到枚举中,以便在项目的 Objective-C 端可以访问它,如下所示:“@objc public enum Bear: Int”
  • @AJit 你为什么要这样做?只需将枚举添加到它自己的标题中并将其导入桥接头中,否则它是 Swift 独有的
  • 此解决方案不适用于 Swift 中的字符串类型枚举。枚举上的@objc 仅适用于整数类型。
【解决方案2】:

扩展所选答案...

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

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

来自 Using Swift with Cocoa and Objective-C

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

目标-C

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

斯威夫特

let cellStyle: UITableViewCellStyle = .Default

【讨论】:

  • 我在 UITableViewCellStyle “这里不允许函数定义”,我做错了什么?当然我有不同的命名而不是 UITableViewCellStyle。
  • 正如 Galasko 先生在下面的回答中所指出的,Swift 1.2 允许在 Swift 中定义枚举并在 Obj-c 中可用。这种定义风格,即 NS_ENUM,在 Obj-c 中仍然有效,但从 Swift 1.2 版开始,您可以使用任一选项。
  • 我发现 Swift 中的 ObjC 枚举存在问题:它们不会失败。在像 if let a = MyEnum(rawValue: 12345) 这样的片段中,其中 12345 不是该枚举的一部分,结果不是可选的,而是一些无效的枚举。
【解决方案3】:

来自Using Swift with Cocoa and Objective-C 指南:

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

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

泛型元组 / 在 Swift 中定义的枚举 / 在中定义的结构 Swift / 顶级函数定义在 Swift / 全局变量定义在 Swift / Swift 中定义的类型别名 / Swift 风格的可变参数 / 嵌套类型 / 柯里化函数

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

【讨论】:

  • 有解决方法吗?我的意思是,如果我创建一个 Swift 类并且我绝对需要一个枚举。如何使该枚举也可用于 Objective-C?
  • @RaulLopezVillalpando 如果您知道您将与 Objective-C 进行互操作,那么您应该在 Objective-C 中声明枚举并让两种语言共享它。
  • “是的,所以我们做了这个桥来帮助你过渡到 Swift,但是如果你想使用任何很酷的东西,比如枚举、结构、泛型......所以就是这样......”跨度>
  • 这个答案不再有效!!从 Xcode 6.3 / Swift 1.2 开始,Swift 枚举也可以在objective-c 中使用@objc,正如@DanielGalasko 在他的回答中指出的那样!!!
  • 只是为了澄清上述评论,引用documentation as of Swift 2.1 上的当前文本,“在 Swift 中定义的枚举没有 Int 原始值类型”。所以,如果你在 Swift 中的枚举是用 @obj enum MyEnum: Int 中的 Int 原始值类型声明的,那么它可以在前面提到的 Objective-C 文件上正常工作。如果你的枚举是用另一个原始值类型声明的,比如@obj enum MyOtherEnum: String,你将不能在 Objective-C 文件中使用它
【解决方案4】:

Swift 4.1,Xcode 9.4.1:

1) Swift 枚举必须以@objc 为前缀并且为Int 类型:

// 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 应该是最后一个?
  • @PaulT。 : 可能与处理顺序有关。试着把它放在别处,你会发现它不起作用。
  • 我检查了,在我当前的项目中,几乎所有文件都在导入部分的末尾,但在几个文件中它不是在末尾并且项目有效。可能在新的 Xcode 中可以正常工作?我现在无法检查它,因为我当前的项目需要很长时间才能编译:),但我会稍后检查它
【解决方案5】:

如果您希望保持 ObjC 代码原样,您可以在项目中添加一个帮助头文件:

Swift2Objc_Helper.h

在头文件中添加这个枚举类型:

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

您的 .m 文件中可能还有其他地方可以进行更改:包含隐藏的头文件:

#import "[YourProjectName]-Swift.h"

将 [YourProjectName] 替换为您的项目名称。这个头文件将所有 Swift 定义的 @objc 类、枚举暴露给 ObjC。

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

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

【讨论】:

    【解决方案6】:

    如果你(像我一样)真的想使用 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 环境中定义了额外的常量)。

    【讨论】:

      【解决方案7】:

      这可能会有所帮助

      问题陈述:- 我在 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
          }
      

      【讨论】:

        【解决方案8】:

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

        Example Project

        【讨论】:

        • 我看不到,您的项目在哪里使用了 Objective C 中的 swift 枚举。此外,swift 枚举 enum SwAnimal 的定义缺少前导 @obj
        【解决方案9】:

        如果您尝试观察如下所示的枚举:

        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)!
          })
          

        就这样。现在,每次您更改 observable 类中的 _enumName 时,observable 类上的相应实例也会立即更新。

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-08-31
          • 1970-01-01
          • 2014-11-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-09
          • 1970-01-01
          相关资源
          最近更新 更多