如何在 Objective-C 中使用 Swift 字符串枚举?
Posted
技术标签:
【中文标题】如何在 Objective-C 中使用 Swift 字符串枚举?【英文标题】:How to make a Swift String enum available in Objective-C? 【发布时间】:2015-08-09 09:55:32 【问题描述】:我有这个带有 String
值的枚举,它将用于告诉 API 方法记录到服务器的消息具有什么样的服务性。我使用的是 Swift 1.2,所以枚举可以映射到 Objective-C
@objc enum LogSeverity : String
case Debug = "DEBUG"
case Info = "INFO"
case Warn = "WARN"
case Error = "ERROR"
我得到了错误
@objc 枚举原始类型字符串不是整数类型
我还没有找到任何地方说只有整数可以从 Swift 转换为 Objective-C。是这样吗?如果是这样,是否有人对如何在 Objective-C 中提供类似的东西有任何最佳实践建议?
【问题讨论】:
【参考方案1】:其中一种解决方案是使用RawRepresentable
协议。
编写 init 和 rawValue 方法并不理想,但这样您就可以在 Swift 和 Objective-C 中像往常一样使用这个枚举。
@objc public enum LogSeverity: Int, RawRepresentable
case debug
case info
case warn
case error
public typealias RawValue = String
public var rawValue: RawValue
switch self
case .debug:
return "DEBUG"
case .info:
return "INFO"
case .warn:
return "WARN"
case .error:
return "ERROR"
public init?(rawValue: RawValue)
switch rawValue
case "DEBUG":
self = .debug
case "INFO":
self = .info
case "WARN":
self = .warn
case "ERROR":
self = .error
default:
return nil
【讨论】:
我真的很喜欢这种方法。为了使其完美,可以通过定义[LogSeverity: String]
类型的字典来避免一些代码重复,然后可以在一行中定义rawValue
和init?
方法。
@Gobe 你能分享一下如何编写 rawValue 和 init 的例子吗?请把方法放在一行中好吗?
@DanielSanchez 如果你有一个 LogSeverity
类型的枚举,它可以由 String
s 原始表示,并且你定义了一次 [LogSeverity: String]
类型的字典,那么 rawValue 就是 myDictionary[self]
初始化是self = myDictionary.first(where: $0.value == rawValue )
这似乎是一个不错的答案,但我在尝试后遇到了奇怪的 bad_access 崩溃。
@VladimirsMatusevics 我修复了它并请求编辑,tnx 进行更正【参考方案2】:
来自Xcode 6.3 release notes(已添加重点):
Swift 语言增强
... 现在可以使用 @objc 将 Swift 枚举导出到 Objective-C 属性。 @objc enums 必须声明一个整数原始类型,并且不能是 通用或使用关联值。因为 Objective-C 枚举不是 命名空间,枚举案例被导入到 Objective-C 作为 枚举名称和案例名称的串联。
【讨论】:
链接上找不到页面【参考方案3】:这是一个可行的解决方案。
@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"
【讨论】:
在Objective-C中如何调用name()
函数?
@David 但你不能在 objc 中调用 name()
@Chuck 即使是公共函数也不会暴露方法。
不知道为什么这个答案被投票了,这不能从 Obj-C 访问
是的,我也不能从 objc 调用【参考方案4】:
如果您真的想实现目标,这里有一些解决方法。但是,您可以访问 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()
打电话:
NSString *debugRawValue = [LogSeverityBridge Debug]
【讨论】:
我看到的问题是你不能拥有 LogSeverity 类型的variables
,否则就可以了。
这对我有用,只是做了一些小的改动。 @objcMembers public class LogSeverityBridge: NSObject static func debug() -> String return TravelerProtectionLevel.premium.rawValue
【参考方案5】:
如果您不介意在 (Objective) C 中定义值,可以使用 NS_TYPED_ENUM
宏在 Swift 中导入常量。
例如:
.h 文件
typedef NSString *const ProgrammingLanguage NS_TYPED_ENUM;
FOUNDATION_EXPORT ProgrammingLanguage ProgrammingLanguageSwift;
FOUNDATION_EXPORT ProgrammingLanguage ProgrammingLanguageObjectiveC;
.m 文件
ProgrammingLanguage ProgrammingLanguageSwift = "Swift";
ProgrammingLanguage ProgrammingLanguageObjectiveC = "ObjectiveC";
在 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
虽然该类型没有桥接为enum
,但在Swift代码中使用时感觉非常相似。
您可以在Using Swift with Cocoa and Objective-C documentation 的“与 C API 交互”中阅读有关此技术的更多信息
【讨论】:
这正是我一直在寻找的方法!【参考方案6】: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"
【讨论】:
【参考方案7】:这是我的用例:
我尽可能避免使用硬编码字符串,以便在更改某些内容时收到编译警告 我有一个来自后端的固定字符串值列表,也可以是 nil这是我的解决方案,完全不涉及硬编码字符串,支持缺失值,并且可以在 Swift 和 Obj-C 中优雅地使用:
@objc enum InventoryItemType: Int
private enum StringInventoryItemType: String
case vial
case syringe
case crystalloid
case bloodProduct
case supplies
case vial
case syringe
case crystalloid
case bloodProduct
case supplies
case unknown
static func fromString(_ string: String?) -> InventoryItemType
guard let string = string else
return .unknown
guard let stringType = StringInventoryItemType(rawValue: string) else
return .unknown
switch stringType
case .vial:
return .vial
case .syringe:
return .syringe
case .crystalloid:
return .crystalloid
case .bloodProduct:
return .bloodProduct
case .supplies:
return .supplies
var stringValue: String?
switch self
case .vial:
return StringInventoryItemType.vial.rawValue
case .syringe:
return StringInventoryItemType.syringe.rawValue
case .crystalloid:
return StringInventoryItemType.crystalloid.rawValue
case .bloodProduct:
return StringInventoryItemType.bloodProduct.rawValue
case .supplies:
return StringInventoryItemType.supplies.rawValue
case .unknown:
return nil
【讨论】:
我不能使用来自 Objective-C 的[InventoryItemType fromString:]
:它给出错误“接收器类型 'InventoryItemType' 不是 Objective-C 类”
那是因为在 Objective-C 中 InventoryItemType 将是 Int 或 NSInteger 类型,它不是一个类。
嗨@ChrisGarrett 我得到了这样的枚举:public enum TrackingValue case constant(String) case customVariable(name: String) case defaultVariable(DefaultVariable) public enum DefaultVariable case advertisingId case advertisingTrackingEnabled case appVersion case connectionType case interfaceOrientation case isFirstEventAfterAppUpdate case requestQueueSize case adClearId
让它被视为ObjC枚举的最佳方法是什么?提前致谢!
@agirault 您可以将其包装在另一个类中,例如class InventoryItemTypeParser: NSObject @objc static func fromString(_ string: String?) -> InventoryItemType return InventoryItemType.fromString(string)
【参考方案8】:
我认为@Remi 的答案在某些情况下会崩溃,因为我有这个:
My error's screesshot。所以我为@Remi 的回答发布了我的版本:
@objc public enum LogSeverity: Int, RawRepresentable
case debug
case info
case warn
case error
public typealias RawValue = String
public var rawValue: RawValue
switch self
case .debug:
return "DEBUG"
case .info:
return "INFO"
case .warn:
return "WARN"
case .error:
return "ERROR"
public init?(rawValue: RawValue)
switch rawValue
case "DEBUG":
self = .debug
case "INFO":
self = .info
case "WARN":
self = .warn
case "ERROR":
self = .error
default:
return nil
【讨论】:
有什么方法可以从 Objc 创建这个枚举,当我尝试 [LogSeverity rawValue:] 它没有找到初始化程序。 如何从目标 c 访问字符串值?【参考方案9】:这就是我想出的。在我的例子中,这个枚举是在为特定类提供信息的上下文中,ServiceProvider
。
class ServiceProvider
@objc enum FieldName : Int
case CITY
case LATITUDE
case LONGITUDE
case NAME
case GRADE
case POSTAL_CODE
case STATE
case REVIEW_COUNT
case COORDINATES
var string: String
return ServiceProvider.FieldNameToString(self)
class func FieldNameToString(fieldName:FieldName) -> String
switch fieldName
case .CITY: return "city"
case .LATITUDE: return "latitude"
case .LONGITUDE: return "longitude"
case .NAME: return "name"
case .GRADE: return "overallGrade"
case .POSTAL_CODE: return "postalCode"
case .STATE: return "state"
case .REVIEW_COUNT: return "reviewCount"
case .COORDINATES: return "coordinates"
在 Swift 中,您可以在枚举上使用 .string
(类似于 .rawValue
)。
在 Objective-C 中,您可以使用 [ServiceProvider FieldNameToString:enumValue];
【讨论】:
【参考方案10】:您可以创建一个私有的Inner
枚举。该实现有点可重复,但清晰易懂。 1 行 rawValue
,2 行 init
,它们看起来总是一样的。 Inner
有一个方法返回“外部”等价物,反之亦然。
与此处的其他答案不同,您可以将枚举案例直接映射到 String
的额外好处。
如果您知道如何解决模板的可重复性问题,欢迎您在此答案的基础上再接再厉,我现在没有时间讨论它。
@objc enum MyEnum: NSInteger, RawRepresentable, Equatable
case
option1,
option2,
option3
// MARK: RawRepresentable
var rawValue: String
return toInner().rawValue
init?(rawValue: String)
guard let value = Inner(rawValue: rawValue)?.toOuter() else return nil
self = value
// MARK: Obj-C support
private func toInner() -> Inner
switch self
case .option1: return .option1
case .option3: return .option3
case .option2: return .option2
private enum Inner: String
case
option1 = "option_1",
option2 = "option_2",
option3 = "option_3"
func toOuter() -> MyEnum
switch self
case .option1: return .option1
case .option3: return .option3
case .option2: return .option2
【讨论】:
以上是关于如何在 Objective-C 中使用 Swift 字符串枚举?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Objective-C 中使用 Swift 字符串枚举?
如何在 Flutter 插件的 Swift 编写的 iOS 部分中使用 Objective-C 框架