Swift has the OptionSet type, which basically adds set operations to C-Style bit flags. Apple is using them pretty extensively in their frameworks. Examples include the options
This article in NSHipster gives an alternative to OptionSet that offers all the features of an OptionSet, plus easy logging:
https://nshipster.com/optionset/
If you simply add a requirement that the Option type be CustomStringConvertible, you can log Sets of this type very cleanly. Below is the code from the NSHipster site - the only change being the addition of CustomStringConvertible
conformance to the Option
class
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 {
return [.pepperoni, .bacon]
}
static var hawaiian: Set {
return [.pineapple, .bacon]
}
static var all: Set {
return Set(Element.allCases)
}
}
typealias Toppings = Set
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
}
}
Then using it:
let toppings: Set = [.onions, .bacon]
print("toppings = \(toppings), rawValue = \(toppings.rawValue)")
That outputs
toppings = [.onions, .bacon], rawValue = 6
Just like you want it to.
That works because a Set displays its members as a comma-delimited list inside square brackets, and uses the description
property of each set member to display that member. The description
property simply displays each item (the enum's name as a String
) with a .
prefix
And since the rawValue of a Set
is the same as an OptionSet with the same list of values, you can convert between them readily.
I wish Swift would just make this a native language feature for OptionSet
s.