原文链接:http://nshipster.com/rawoptionsettype/
用法
OC中用NS_ENUM & NS_OPTIONS
用来标记C中的枚举值。
在Swift中,即使因为增加了许多特性让枚举显得比较费事比如原始值和关联值等,枚举仍然以第一类语言的身份与struct or class
并驾齐驱成为基石。枚举完全的契合使用于封装一套关系相近的固定值集合,开发可以有很多机会来使用它们。
当在Swift中使用Foundation
类似框架的时候,所有的NS_ENUM
声明自动转换成了enum
,并且减少了OC中命名的重复度:
enum UITableViewCellStyle : Int {
case Default
case Value1
case Value2
case Subtitle
}
不幸的是,对于NS_OPTIONS
,Swift等价转换就有点吃力了:
struct UIViewAutoresizing : RawOptionSetType {
init(_ value: UInt)
var value: UInt
static var None: UIViewAutoresizing { get }
static var FlexibleLeftMargin: UIViewAutoresizing { get }
static var FlexibleWidth: UIViewAutoresizing { get }
static var FlexibleRightMargin: UIViewAutoresizing { get }
static var FlexibleTopMargin: UIViewAutoresizing { get }
static var FlexibleHeight: UIViewAutoresizing { get }
static var FlexibleBottomMargin: UIViewAutoresizing { get }
}
RawOptionsSetType
是Swift中与NS_OPTIONS
等价(至少是相近)的东东。它是一个协议遵循RawRepresentable, Equatable, BitwiseOperationsType, 和 NilLiteralConvertible
等协议。一个可选类型可以用遵循BitwiseOperationsType
的struct
结构数据来表示。
为什么这么操蛋呢?好吧,同样C语言中整型比特掩码技巧在Swift枚举型中不起作用。一个枚举表示一套固定的值,而同时没有内部的机制表示这种类型值联合值。一个枚举值表面上可以定义所有可能性的联合值范围,但是对于n > 3这种,这样的组合方式是不能实现的。这里有另外的方式来让Swift中等价实现OC中的NS_OPTIONS
,但是RawOptionSetType
是坏种最好的。
对比句法上精确的enum
类声明,RawOptionsSetType
确实是使用不便并且冗余,这里指需要多行的模板代码实现属性值计算:
truct Toppings : RawOptionSetType, BooleanType {
private var value: UInt = 0
init(_ value: UInt) {
self.value = value
}
// MARK: RawOptionSetType
static func fromMask(raw: UInt) -> Toppings {
return self(raw)
}
// MARK: RawRepresentable
static func fromRaw(raw: UInt) -> Toppings? {
return self(raw)
}
func toRaw() -> UInt {
return value
}
// MARK: BooleanType
var boolValue: Bool {
return value != 0
}
// MARK: BitwiseOperationsType
static var allZeros: Toppings {
return self(0)
}
// MARK: NilLiteralConvertible
static func convertFromNilLiteral() -> Toppings {
return self(0)
}
// MARK: -
static var None: Toppings { return self(0b0000) }
static var ExtraCheese: Toppings { return self(0b0001) }
static var Pepperoni: Toppings { return self(0b0010) }
static var GreenPepper: Toppings { return self(0b0100) }
static var Pineapple: Toppings { return self(0b1000) }
}
As of Xcode 6 Beta 6, RawOptionSetType no longer conforms to BooleanType, which is required for performing bitwise checks.
庆幸的是Swift的内置二进制整型标记可以让二进制掩码显式计算。并且只要可选型枚举定义过了,使用起来还不算太费事。。。
struct Pizza {
enum Style {
case Neopolitan, Sicilian, NewHaven, DeepDish
}
struct Toppings : RawOptionSetType { ... }
let diameter: Int
let style: Style
let toppings: Toppings
init(inchesInDiameter diameter: Int, style: Style, toppings: Toppings = .None) {
self.diameter = diameter
self.style = style
self.toppings = toppings
}
}
let dinner = Pizza(inchesInDiameter: 12, style: .Neopolitan, toppings: .Pepperoni | .GreenPepper)
检验可选枚举值是否满足某个可选条件可以像C语言一样使用符号&
:
extension Pizza {
var isVegetarian: Bool {
return toppings & Toppings.Pepperoni ? false : true
}
}
dinner.isVegetarian // false
最后
吐槽。。。略
举个NS_OPTIONS
等价代码的栗子:
struct <# Options #> : RawOptionSetType, BooleanType {
private var value: UInt = 0
init(_ value: UInt) { self.value = value }
var boolValue: Bool { return value != 0 }
static func fromMask(raw: UInt) -> <# Options #> { return self(raw) }
static func fromRaw(raw: UInt) -> <# Options #>? { return self(raw) }
func toRaw() -> UInt { return value }
static var allZeros: <# Options #> { return self(0) }
static func convertFromNilLiteral() -> <# Options #> { return self(0) }
static var None: <# Options #> { return self(0b0000) }
static var <# Option #>: <# Options #> { return self(0b0001) }
// ...
}