我在Swift中有一个enum Foo: String
(因此无法导出到Objective-C)而我正在尝试在Swift中创建另一个枚举FooObjc
,以便“包裹”现有的一个,以便它是1)可用于Objective-C和2)来回转换(Foo
< => FooObjc
)。原始Foo
枚举是我不想修改的框架的一部分。当然,如果我使用一个类,那么很容易做我想要的事情,比如:
@objc public class FooObjc: NSObject {
public private(set) var foo: Foo
@objc public var string: String {
return foo.rawValue
}
@objc public init?(string: NSString) {
guard let foo = Foo(rawValue: string as String) else {
return nil
}
self.foo = foo
}
internal init(foo: Foo) {
self.foo = foo
}
}
(PS:无法继承NSString
,因为Swift编译器仍然不接受为该类创建初始值设定项)
好的,但我绝对不喜欢这种方法,因为那时我的Objective-C代码将是字符串类型的。我真的想使用enum
,因为毕竟,它就是这样。这是我能得到的最糟糕的工作版本:
@objc public enum FooObjc: Int, RawRepresentable {
case undefined = -1
case bar
case baz
// omitting many more cases
internal init?(_ foo: Foo?) {
if let foo = foo {
self = fooMapping.filter { $1 == foo }.map { $0.key }.first!
} else {
self = .undefined
}
}
// MARK: - RawRepresentable
public typealias RawValue = String
public init?(rawValue: RawValue) {
let filter = fooMapping.filter { $1?.rawValue == rawValue }
guard filter.count > 0 else {
return nil
}
self = filter.map { $0.key }.first!
}
public var rawValue: RawValue {
switch (self) {
case .undefined: return "undefined"
case .bar: return Foo.bar.rawValue
case .baz: return Foo.baz.rawValue
// omitting many more cases
}
}
}
private let fooMapping: [FooObjc: Foo?] = [
.undefined : nil,
.bar : .bar,
.baz : .baz
// omitting many more cases
]
请注意:
fooMapping
对于避免每个初始化程序的一个switch-case非常有用undefined
案例是必要的,因为在Swift中你可以拥有可选的enum
属性,在Objective-C中你不能,所以这种情况将直接映射到Foo?
哪个值是nil
。我担心的是,我必须从最初的Foo 三次次写出相同的案例...如果我只重复两次,我会完全满意,但我不能使用fooMapping
属性中的rawValue
,因为我在这两个属性之间有一个循环。
注意:我不确定这是否与问题相关,但在原始enum
中,某些案例具有特殊的字符串属性,例如:我们只是case bar
但我们也有case baz = "something"
。
所以,问题是:有没有人建议改进这种方法,甚至建议一些可以避免重复代码的全新内容?
非常感谢!
答案 0 :(得分:1)
我担心的是,我必须从原来的Foo写三次相同的案例
考虑一个数组OnPropertyChanged
。通过查看此数组中字符串的索引并进行必要的调整,您可以将字符串转换为整数(从而通过原始值转换为大小写)。通过索引到数组并进行必要的调整,您可以从整数转换为字符串(从而通过原始值转换为大小写)。所以你只需要写出一次字符串值。这消除了你的两次重复。
您仍然需要在枚举声明中写出案例名称,因为没有其他方法可以告诉Objective-C案例的名称。显然,消除 重复的方法是愿意改变Foo本身的实现,以便 it 变得与Objective-C兼容。但你事先已经说过你拒绝这样做,所以现在你必须付出代价。