如何以人类可读的形式显示OptionSet值?

Dun*_*n C 11 ios swift optionsettype

Swift具有OptionSet类型,它基本上将集合操作添加到C样式位标志.Apple在他们的框架中广泛使用它们.示例包括选项参数animate(withDuration:delay:options:animations:completion:).

从好的方面来说,它可以让你使用干净的代码:

options: [.allowAnimatedContent, .curveEaseIn]
Run Code Online (Sandbox Code Playgroud)

但是,也存在不利因素.

如果我想显示一个指定的值OptionSet,似乎没有一个干净的方法来做它:

let options: UIViewAnimationOptions = [.allowAnimatedContent, .curveEaseIn]
print("options = " + String(describing: options))
Run Code Online (Sandbox Code Playgroud)

显示非常无用的消息:

options = UIViewAnimationOptions(rawValue:65664)

其中一些位字段的文档将常量表示为二次幂值:

flag0    = Flags(rawValue: 1 << 0)
Run Code Online (Sandbox Code Playgroud)

但是我的示例OptionSet的文档UIViewAnimationOptions并没有告诉你关于这些标志的数值的任何信息,并且从十进制数中找出位并不是直截了当的.

题:

是否有一些干净的方法将OptionSet映射到选定的值?

我想要的输出是这样的:

options = UIViewAnimationOptions([.allowAnimatedContent,.curveEaseIn])

但是如果没有一堆杂乱的代码需要我为每个标志维护一个显示名称表,我想不出办法做到这一点.

(我有兴趣为我自己的代码中创建的系统框架和自定义OptionSet执行此操作.)

Enums允许您同时拥有枚举的名称和原始值,但这些不支持使用OptionSets获得的set函数.

Dun*_*n C 4

NSHipster 中的这篇文章提供了 OptionSet 的替代方案,它提供了 OptionSet 的所有功能,以及简单的日志记录:

https://nshipster.com/optionset/

如果您只是添加一个要求,即 Option 类型为 CustomStringConvertible,则可以非常干净地记录此类型的 Set。下面是来自 NSHipster 站点的代码 - 唯一的变化是添加了对类的CustomStringConvertible一致性Option

protocol Option: RawRepresentable, Hashable, CaseIterable, CustomStringConvertible {}

enum Topping: String, Option {
    case pepperoni, onions, bacon,
    extraCheese, greenPeppers, pineapple

    //I added this computed property to make the class conform to CustomStringConvertible
    var description: String {
        return ".\(self.rawValue)"
    }
}

extension Set where Element == Topping {
    static var meatLovers: Set<Topping> {
        return [.pepperoni, .bacon]
    }

    static var hawaiian: Set<Topping> {
        return [.pineapple, .bacon]
    }

    static var all: Set<Topping> {
        return Set(Element.allCases)
    }
}

typealias Toppings = Set<Topping>

extension Set where Element: Option {
    var rawValue: Int {
        var rawValue = 0
        for (index, element) in Element.allCases.enumerated() {
            if self.contains(element) {
                rawValue |= (1 << index)
            }
        }
        return rawValue
    }
}
Run Code Online (Sandbox Code Playgroud)

然后使用它:

let toppings: Set<Topping> = [.onions, .bacon]

print("toppings = \(toppings), rawValue = \(toppings.rawValue)")
Run Code Online (Sandbox Code Playgroud)

输出

配料 = [.洋葱,.培根],rawValue = 6

就像你想要的那样。

这是可行的,因为 Set 将其成员显示为方括号内的逗号分隔列表,并使用description每个集合成员的属性来显示该成员。该属性仅显示带有前缀的description每个项目(枚举的名称为 a String.

由于 a 的 rawValueSet<Option>与具有相同值列表的 OptionSet 相同,因此您可以轻松地在它们之间进行转换。

我希望 Swift 能够将其作为 s 的本地语言功能OptionSet