为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

墨色风雨 2019-10-05 15:30:55
在Apple有关与C API交互的文档中,他们描述了将NS_ENUM标记的C样式枚举作为Swift枚举导入的方式。这是有道理的,并且由于Swift中的枚举很容易作为enum值类型提供,因此很容易看到如何创建我们自己的枚举。再往下,它说了关于NS_OPTIONS标记C样式的选项:Swift还会导入标有NS_OPTIONS宏的选项。而选项的行为类似于进口枚举,选项还可以支持一些位操作,如&,|和~。在Objective-C中,您表示一个常量为零(0)的空选项集。在Swift中,用于nil表示没有任何选项。鉴于optionsSwift中没有值类型,我们如何创建要使用的C-Style选项变量?
查看完整描述

3 回答

?
隔江千里

TA贡献1906条经验 获得超10个赞

斯威夫特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)

}

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


let noOptions: 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")

}

斯威夫特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)

}

现在我们可以使用基于集合的语义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")

}

斯威夫特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) }

}

现在,我们可以像对待MyOptions苹果文档中所述的那样对待这个新的选项集:您可以使用enum-like语法:


let opt1 = MyOptions.FirstOption

let opt2: MyOptions = .SecondOption

let opt3 = MyOptions(4)

而且它的行为也像我们期望的选项那样:


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")

}

我已经构建了一个生成器来创建Swift选项集,而无需进行所有查找/替换。


最新:对Swift 1.1 beta 3的修改。


查看完整回答
反对 回复 2019-10-05
?
守候你守候我

TA贡献1802条经验 获得超10个赞

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) }

}

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


let opt1 = MyOptions.FirstOption

let opt2:MyOptions = .SecondOption

let opt3 = MyOptions(4)

像这样测试位:


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")

}


查看完整回答
反对 回复 2019-10-05
  • 3 回答
  • 0 关注
  • 852 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信