【问题标题】:Creating an enum in Swift, exportable to ObjC, based on another enum: String在 Swift 中创建一个枚举,可导出到 ObjC,基于另一个枚举:String
【发布时间】:2016-12-07 16:03:36
【问题描述】:

我在 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 case 是必要的,因为在Swift 中你可以有可选的enum 属性,而在Objective-C 中你不能,所以这个case 将直接映射到一个Foo?,其值为nil

这里让我担心的是,我必须将原始 Foo 的相同案例写三次次......如果我只重复两次,我就完全满意了,但我不能在rawValue 属性中使用fooMapping,因为那样我会在这两者之间得到一个循环。

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

那么,问题是:有没有人提出改进这种方法的建议,甚至提出一些全新的方法来避免如此多的代码重复?

非常感谢!

【问题讨论】:

    标签: objective-c swift enums


    【解决方案1】:

    这里让我担心的是,我不得不从原来的 Foo 中写三遍相同的案例

    考虑一个数组["bar", "baz" ...]。通过查看此数组中字符串的索引并进行必要的调整,您可以将字符串转换为整数(然后通过原始值转换为大小写)。通过对数组进行索引并进行必要的调整,您可以将整数转换为字符串(然后通过原始值转换为大小写)。因此,您只需写出字符串值一次。这消除了您的两次重复。

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

    【讨论】:

    • 谢谢@matt,是的,你在第二段中所说的正是我说“如果我只重复两次,我就完全满意了”的确切原因,因为我正在计算我自己的枚举案例声明已为一。您的方法似乎是一个非常好的主意,我会尝试一下并很快接受答案:) 现在投票。
    • 如果情况更复杂,我们仍然可以使用元组数组或其他将字符串及其对应整数结合起来的对来解决它。但似乎没有必要这样做;数组中的索引号就可以了。
    猜你喜欢
    • 2014-10-09
    • 2017-04-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多