如何在Swift中创建NS_OPTIONS样式的位掩码枚举?

Nat*_*ook 128 bitwise-operators ios swift

在Apple关于与C API交互的文档中,他们描述了NS_ENUM以Swift枚举方式导入标记的C风格枚举的方式.这是有道理的,因为Swift中的枚举很容易作为enum值类型提供,所以很容易看到如何创建自己的.

更进一步,它说这是关于NS_OPTIONS标记的C风格选项:

Swift还导入标有NS_OPTIONS宏的选项.而选项的行为类似于进口枚举,选项还可以支持一些位操作,如&,|~.在Objective-C中,表示使用常量零(0)设置的空选项.在Swift中,用于nil表示没有任何选项.

鉴于optionsSwift中没有值类型,我们如何创建一个C-Style选项变量来使用?

Nat*_*ook 250

Swift 3.0

几乎与Swift 2.0完全相同.OptionSetType已重命名为OptionSet,枚举按约定写成小写.

struct MyOptions : OptionSet {
    let rawValue: Int

    static let firstOption  = MyOptions(rawValue: 1 << 0)
    static let secondOption = MyOptions(rawValue: 1 << 1)
    static let thirdOption  = MyOptions(rawValue: 1 << 2)
}
Run Code Online (Sandbox Code Playgroud)

noneSwift 3建议使用空数组文字,而不是提供选项:

let noOptions: MyOptions = []
Run Code Online (Sandbox Code Playgroud)

其他用途:

let singleOption = MyOptions.firstOption
let multipleOptions: MyOptions = [.firstOption, .secondOption]
if multipleOptions.contains(.secondOption) {
    print("multipleOptions has SecondOption")
}
let allOptions = MyOptions(rawValue: 7)
if allOptions.contains(.thirdOption) {
    print("allOptions has ThirdOption")
}
Run Code Online (Sandbox Code Playgroud)

Swift 2.0

在Swift 2.0中,协议扩展负责处理这些的大部分样板,现在它们作为符合的结构导入OptionSetType.(RawOptionSetType从Swift 2 beta 2开始消失了.)声明要简单得多:

struct MyOptions : OptionSetType {
    let rawValue: Int

    static let None         = MyOptions(rawValue: 0)
    static let FirstOption  = MyOptions(rawValue: 1 << 0)
    static let SecondOption = MyOptions(rawValue: 1 << 1)
    static let ThirdOption  = MyOptions(rawValue: 1 << 2)
}
Run Code Online (Sandbox Code Playgroud)

现在我们可以使用基于集合的语义MyOptions:

let singleOption = MyOptions.FirstOption
let multipleOptions: MyOptions = [.FirstOption, .SecondOption]
if multipleOptions.contains(.SecondOption) {
    print("multipleOptions has SecondOption")
}
let allOptions = MyOptions(rawValue: 7)
if allOptions.contains(.ThirdOption) {
    print("allOptions has ThirdOption")
}
Run Code Online (Sandbox Code Playgroud)

Swift 1.2

看着由夫特导入的(Objective-C的选项UIViewAutoresizing,例如),我们可以看到,选项被声明为struct符合协议RawOptionSetType,这反过来又符合 _RawOptionSetType,Equatable,RawRepresentable,BitwiseOperationsType,和NilLiteralConvertible.我们可以像这样创建自己的:

struct MyOptions : RawOptionSetType {
    typealias RawValue = UInt
    private var value: UInt = 0
    init(_ value: UInt) { self.value = value }
    init(rawValue value: UInt) { self.value = value }
    init(nilLiteral: ()) { self.value = 0 }
    static var allZeros: MyOptions { return self(0) }
    static func fromMask(raw: UInt) -> MyOptions { return self(raw) }
    var rawValue: UInt { return self.value }

    static var None: MyOptions { return self(0) }
    static var FirstOption: MyOptions   { return self(1 << 0) }
    static var SecondOption: MyOptions  { return self(1 << 1) }
    static var ThirdOption: MyOptions   { return self(1 << 2) }
}
Run Code Online (Sandbox Code Playgroud)

现在我们可以处理这个新的选项集,MyOptions就像在Apple的文档中描述的那样:你可以使用类似enum语法:

let opt1 = MyOptions.FirstOption
let opt2: MyOptions = .SecondOption
let opt3 = MyOptions(4)
Run Code Online (Sandbox Code Playgroud)

它的行为也像我们期望的行为选择:

let singleOption = MyOptions.FirstOption
let multipleOptions: MyOptions = singleOption | .SecondOption
if multipleOptions & .SecondOption != nil {     // see note
    println("multipleOptions has SecondOption")
}
let allOptions = MyOptions.fromMask(7)   // aka .fromMask(0b111)
if allOptions & .ThirdOption != nil {
    println("allOptions has ThirdOption")
}
Run Code Online (Sandbox Code Playgroud)

我已经构建了一个生成器来创建一个没有所有查找/替换的Swift选项集.

最新: Swift 1.1 beta 3的修改.

  • 有没有使用枚举而不是结构的解决方案?我需要我的兼容Objective-c ... (2认同)

Kla*_*aas 12

Xcode 6.1 Beta 2对RawOptionSetType协议进行了一些更改(请参阅此Airspeedvelocity博客条目Apple发行说明).

基于Nate Cooks的例子,这里有一个更新的解决方案.您可以像这样定义自己的选项集:

struct MyOptions : RawOptionSetType, BooleanType {
    private var value: UInt
    init(_ rawValue: UInt) { self.value = rawValue }

    // MARK: _RawOptionSetType
    init(rawValue: UInt) { self.value = rawValue }

    // MARK: NilLiteralConvertible
    init(nilLiteral: ()) { self.value = 0}

    // MARK: RawRepresentable
    var rawValue: UInt { return self.value }

    // MARK: BooleanType
    var boolValue: Bool { return self.value != 0 }

    // MARK: BitwiseOperationsType
    static var allZeros: MyOptions { return self(0) }

    // MARK: User defined bit values
    static var None: MyOptions          { return self(0) }
    static var FirstOption: MyOptions   { return self(1 << 0) }
    static var SecondOption: MyOptions  { return self(1 << 1) }
    static var ThirdOption: MyOptions   { return self(1 << 2) }
    static var All: MyOptions           { return self(0b111) }
}
Run Code Online (Sandbox Code Playgroud)

然后可以像这样使用它来定义变量:

let opt1 = MyOptions.FirstOption
let opt2:MyOptions = .SecondOption
let opt3 = MyOptions(4)
Run Code Online (Sandbox Code Playgroud)

像这样测试位:

let singleOption = MyOptions.FirstOption
let multipleOptions: MyOptions = singleOption | .SecondOption
if multipleOptions & .SecondOption {
    println("multipleOptions has SecondOption")
}

let allOptions = MyOptions.All
if allOptions & .ThirdOption {
    println("allOptions has ThirdOption")
}
Run Code Online (Sandbox Code Playgroud)


Tom*_*Bąk 8

文档中的Swift 2.0示例:

struct PackagingOptions : OptionSetType {
    let rawValue: Int
    init(rawValue: Int) { self.rawValue = rawValue }

    static let Box = PackagingOptions(rawValue: 1)
    static let Carton = PackagingOptions(rawValue: 2)
    static let Bag = PackagingOptions(rawValue: 4)
    static let Satchel = PackagingOptions(rawValue: 8)
    static let BoxOrBag: PackagingOptions = [Box, Bag]
    static let BoxOrCartonOrBag: PackagingOptions = [Box, Carton, Bag]
}
Run Code Online (Sandbox Code Playgroud)

你可以在这里找到它


ric*_*ter 6

在Swift 2中(目前作为Xcode 7 beta的一部分测试版),NS_OPTIONS-style类型被导入为新OptionSetType类型的子类型.由于新的Protocol Extensions功能以及OptionSetType在标准库中实现的方式,您可以声明自己的类型,这些类型可以扩展OptionsSetType并获得导入NS_OPTIONS类型获得的所有相同的函数和方法.

但是这些函数不再基于按位算术运算符.在C中使用一组非排他性布尔选项需要在字段中屏蔽和修整位是一个实现细节.实际上,一组选项是一 ......一组独特的项目.因此OptionsSetTypeSetAlgebraType协议中获取所有方法,例如从数组文字语法创建,查询contains,屏蔽intersection等等.(不再需要记住哪个有趣的字符用于哪个成员资格测试!)


小智 5

//Swift 2.0
 //create
    struct Direction : OptionSetType {
        let rawValue: Int
        static let None   = Direction(rawValue: 0)
        static let Top    = Direction(rawValue: 1 << 0)
        static let Bottom = Direction(rawValue: 1 << 1)
        static let Left   = Direction(rawValue: 1 << 2)
        static let Right  = Direction(rawValue: 1 << 3)
    }
//declare
var direction: Direction = Direction.None
//using
direction.insert(Direction.Right)
//check
if direction.contains(.Right) {
    //`enter code here`
}
Run Code Online (Sandbox Code Playgroud)