如何在Objective-C中提供Swift String枚举?

bog*_*gen 58 enums interop objective-c swift

我有这个带有String值的枚举,它将用于告诉API方法记录服务器消息具有什么样的服务器性.我正在使用Swift 1.2,因此枚举可以映射到Objective-C

@objc enum LogSeverity : String {
    case Debug = "DEBUG"
    case Info = "INFO"
    case Warn = "WARN"
    case Error = "ERROR"
}
Run Code Online (Sandbox Code Playgroud)

我收到了错误

@objc enum raw type String不是整数类型

我没有设法找到任何说只有整数可以从Swift转换为Objective-C的地方.是这样的吗?如果是这样,有没有人有任何关于如何在Objective-C中提供这样的东西的最佳实践建议?

Rem*_*lia 57

其中一个解决方案是使用RawRepresentable协议.

编写init和rawValue方法并不理想,但允许您像往常一样在Swift和Objective-C中使用此枚举.

@objc public enum LogSeverity: Int, RawRepresentable {
    case debug
    case info
    case warn
    case error

    struct Constants {
        static let routes: [LogSeverity: String] = [
            .debug: "DEBUG",
            .info: "INFO",
            .warn: "WARN",
            .error: "ERROR"
        ]
    }

    public typealias RawValue = String

    public var rawValue: RawValue {
        guard let value = Constants.routes[self] else {
            fatalError("constants definition is missing: \(self)")
        }
        return value
    }

    public init?(rawValue: RawValue) {
        guard let severity = Constants.routes.first(where: { $0.value == rawValue }) else {
            return nil
        }
        self = severity.key
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我真的很喜欢这种方法.为了使其完美,可以通过定义类型为`[LogSeverity:String]`的字典来避免某些代码重复,然后可以用单行定义`rawValue`和`init?`方法. (8认同)
  • rawValue 在 objc 中不可访问。 (3认同)
  • @Gobe你能分享一下如何编写rawValue和init的例子吗?方法在一行中,好吗? (2认同)
  • @DanielSanchez 如果你有一个 `LogSeverity` 类型的枚举,它可以由 `String`s 原始表示,并且你定义了一个 `[LogSeverity: String]` 类型的字典,那么 rawValue 就是 `myDictionary[self]` 和init 是 `self = myDictionary.first(where: { $0.value == rawValue })` (2认同)

Mar*_*n R 49

Xcode 6.3发行说明(重点补充):

快速语言增强功能

...
现在可以使用@objc属性将Swift枚举导出到Objective-C.@objc枚举必须声明整数原始类型,并且不能是通用的或使用关联的值.因为Objective-C枚举不是命名空间,所以枚举案例被导入到Objective-C中作为枚举名称和案例名称的串联.


Dav*_*vid 22

这是一个有效的解决方案.

@objc public enum ConnectivityStatus: Int {
    case Wifi
    case Mobile
    case Ethernet
    case Off

    func name() -> String {
        switch self {
        case .Wifi: return "wifi"
        case .Mobile: return "mobile"
        case .Ethernet: return "ethernet"
        case .Off: return "off"
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如何在Objective-C中调用`name()`函数? (11认同)
  • @David但你不能在objc中调用`name()` (8认同)
  • 不知道为什么这个答案被投票了,这无法从 Obj-C 访问 (4认同)

BLC*_*BLC 8

如果你真的想要实现这个目标,这就是解决方法.但是,您可以访问Objective C接受的对象中的枚举值,而不是实际的枚举值.

enum LogSeverity : String {

    case Debug = "DEBUG"
    case Info = "INFO"
    case Warn = "WARN"
    case Error = "ERROR"

    private func string() -> String {
        return self.rawValue
    }
}

@objc
class LogSeverityBridge: NSObject {

    class func Debug() -> NSString {
        return LogSeverity.Debug.string()
    }

    class func Info() -> NSString {
        return LogSeverity.Info.string()
    }

    class func Warn() -> NSString {
        return LogSeverity.Warn.string()
    }

    class func Error() -> NSString {
        return LogSeverity.Error.string()
    }
}
Run Code Online (Sandbox Code Playgroud)

致电:

NSString *debugRawValue = [LogSeverityBridge Debug]
Run Code Online (Sandbox Code Playgroud)

  • 这对我来说做了一些小的改动。`@objcMembers公共类LogSeverityBridge:NSObject {静态函数debug()->字符串{return TravelerProtectionLevel.premium.rawValue}` (2认同)

Dan*_*ark 5

Xcode 8 的代码,使用Int有效但其他方法未公开给 Objective-C的事实。这实在是太可怕了……

class EnumSupport : NSObject {
    class func textFor(logSeverity severity: LogSeverity) -> String {
        return severity.text()
    }
}

@objc public enum LogSeverity: Int {
    case Debug
    case Info
    case Warn
    case Error

    func text() -> String {
        switch self {
            case .Debug: return "debug"
            case .Info: return "info"
            case .Warn: return "warn"
            case .Error: return "error"
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Rvd*_*vdB 5

如果您不介意在(Objective)C中定义值,则可以使用NS_TYPED_ENUM宏在Swift中导入常量。

例如:

.h文件

typedef NSString *const ProgrammingLanguage NS_TYPED_ENUM;

FOUNDATION_EXPORT ProgrammingLanguage ProgrammingLanguageSwift;
FOUNDATION_EXPORT ProgrammingLanguage ProgrammingLanguageObjectiveC;
Run Code Online (Sandbox Code Playgroud)

.m文件

ProgrammingLanguage ProgrammingLanguageSwift = "Swift";
ProgrammingLanguage ProgrammingLanguageObjectiveC = "ObjectiveC";
Run Code Online (Sandbox Code Playgroud)

在Swift中,它是这样导入的struct

struct ProgrammingLanguage: RawRepresentable, Equatable, Hashable {
    typealias RawValue = String

    init(rawValue: RawValue)
    var rawValue: RawValue { get }

    static var swift: ProgrammingLanguage { get }
    static var objectiveC: ProgrammingLanguage { get }
}
Run Code Online (Sandbox Code Playgroud)

尽管该类型未作为桥接enum,但在Swift代码中使用它时却感觉非常相似。

您可以在结合使用Swift和Cocoa和Objective-C文档的“与C API交互”中阅读有关此技术的更多信息。