在Swift中创建枚举,可导出到ObjC,基于另一个枚举:String

时间:2016-12-07 16:03:36

标签: objective-c swift enums

我在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
]

请注意:

  1. fooMapping对于避免每个初始化程序的一个switch-case非常有用
  2. 这个undefined案例是必要的,因为在Swift中你可以拥有可选的enum属性,在Objective-C中你不能,所以这种情况将直接映射到Foo?哪个值是nil
  3. 我担心的是,我必须从最初的Foo 三次次写出相同的案例...如果我只重复两次,我会完全满意,但我不能使用fooMapping属性中的rawValue,因为我在这两个属性之间有一个循环。

    注意:我不确定这是否与问题相关,但在原始enum中,某些案例具有特殊的字符串属性,例如:我们只是case bar但我们也有case baz = "something"

    所以,问题是:有没有人建议改进这种方法,甚至建议一些可以避免重复代码的全新内容?

    非常感谢!

1 个答案:

答案 0 :(得分:1)

  

我担心的是,我必须从原来的Foo写三次相同的案例

考虑一个数组OnPropertyChanged。通过查看此数组中字符串的索引并进行必要的调整,您可以将字符串转换为整数(从而通过原始值转换为大小写)。通过索引到数组并进行必要的调整,您可以从整数转换为字符串(从而通过原始值转换为大小写)。所以你只需要写出一次字符串值。这消除了你的两次重复。

您仍然需要在枚举声明中写出案例名称,因为没有其他方法可以告诉Objective-C案例的名称。显然,消除 重复的方法是愿意改变Foo本身的实现,以便 it 变得与Objective-C兼容。但你事先已经说过你拒绝这样做,所以现在你必须付出代价。