在Swift中导入NS_OPTIONS(RawOptionSetType)的语句?

时间:2014-08-19 16:05:09

标签: swift switch-statement enumeration

Swift中的switch语句更具表现力。我想知道这是否可行:

让我们看一下UIViewAutoresizing。它在Objective-C中的定义如下:

typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
    UIViewAutoresizingNone                 = 0,
    UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
    UIViewAutoresizingFlexibleWidth        = 1 << 1,
    UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
    UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
    UIViewAutoresizingFlexibleHeight       = 1 << 4,
    UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};

我可以像在枚举中一样在Swift中使用它:

let foo = UIViewAutoresizing([.FlexibleHeight, .FlexibleTopMargin])

是否可以使用switch语句而不是多个if语句?

if foo & UIViewAutoresizing.FlexibleHeight != nil {

}

if foo & UIViewAutoresizing.FlexibleWidth != nil {

}

if foo & UIViewAutoresizing.FlexibleTopMargin != nil {

}

像这样的伪代码:

switch foo { // ** THIS IS PSEUDO CODE AND WILL NOT COMPILE **

case & .FlexibleHeight:
    println("height")

case & .FlexibleWidth:
    println("width")

case & .FlexibleTop:
    println("top")

}

4 个答案:

答案 0 :(得分:1)

我昨天和今天试了好几个小时才开始工作 - 没有成功。

原因是在这种特殊情况下我们需要针对几种情况进行测试。在Swift中,我们需要使用fallthrough关键字。但是如果下一个案例使用变量,我们就不允许进入下一个案例,因为我们不能使用case let where语句,如下所示:

switch foo {
case let x where x & .FlexibleHeight != nil:
    println("height")
case let x where x & .FlexibleWidth != nil:
    println("width")
case let x where x & .FlexibleTopMargin != nil:
    println("top margin")
default:
    println("no")
}

一旦案件触发,这将爆发。但

switch foo {
case let x where x & .FlexibleHeight != nil:
    println("height")
    fallthrough

case let x where x & .FlexibleWidth != nil:
    println("width")
    fallthrough

case let x where x & .FlexibleTopMargin != nil:
    println("top margin")
default:
    println("no")
}
由于上述原因,

不起作用。


我会使用明确的if语句,例如

let foo = UIViewAutoresizing.FlexibleLeftMargin | UIViewAutoresizing.FlexibleHeight

let width = foo & UIViewAutoresizing.FlexibleWidth;
let height = foo & UIViewAutoresizing.FlexibleHeight;

if width == .FlexibleWidth {
    println("width")
}

if height == .FlexibleHeight {
    println("height")
}

let foo = UIViewAutoresizing.FlexibleLeftMargin | UIViewAutoresizing.FlexibleHeight

let usesFlexibleWidth = (foo & UIViewAutoresizing.FlexibleWidth) != nil;
let usesFlexibleHeight = (foo & UIViewAutoresizing.FlexibleHeight) != nil;

if usesFlexibleWidth {
    println("width")
}

if usesFlexibleHeight {
    println("height")
}

答案 1 :(得分:1)

我对这个问题感到很沮丧,我编写了一个可以处理这些用例的Bitmask<T>类。代码在Github上发布:brynbellomy/SwiftBitmask

它允许你用任何类型的对象作为基础类型(这里我使用的是enum)来做这样的事情:

enum MonsterAttributes : IBitmaskRepresentable, IAutoBitmaskable {
    case Big, Ugly, Scary

    static var autoBitmaskValues : [MonsterAttributes] = [.Big, .Ugly, .Scary,]
    var  bitmaskValue: UInt16  { return AutoBitmask..autoBitmaskValueFor(self) }
    init(bitmaskValue: UInt16) { self = AutoBitmask.autoValueFromBitmask(bitmaskValue) }
}

// various ways to initialize
let option : MonsterAttributes = .Ugly

let bitmaskOfOption        = Bitmask(option)
let anotherBitmaskOfOption = |MonsterAttributes.Ugly // same as bitmaskOfOption

let orWithVar = option | .Big                 // == Bitmask<MonsterAttributes> with a bitmaskValue of 1 | 2
let simpleOr  = MonsterAttributes.Big | .Ugly // == Bitmask<MonsterAttributes> with a bitmaskValue of 1 | 2

// getting the raw integral bitmask value
let simpleOrValue = simpleOr.bitmaskValue                        // == UInt16(1 | 2)
let orValue       = (MonsterAttributes.Big | .Ugly).bitmaskValue // == UInt16(1 | 2)

// implements BooleanType
if simpleOr & .Ugly             { /* this code will execute */ }

// supports pattern matching operator
if simpleOr ~= .Ugly            { /* this code will execute */ }
if simpleOr ~= (.Ugly | .Scary) { /* this code will execute */ }

...而你所要做的就是实现一个属性协议。

如果有人对代码有任何反馈意见或想法,我真的很好奇,所以如果您有任何想法,请在队列中留下问题!

答案 2 :(得分:0)

你绝对可以,虽然RawOptionSetType没有实现BooleanType协议现在有点复杂。

switch foo {
case let x where x & .FlexibleHeight != nil:
    println("height")
case let x where x & .FlexibleWidth != nil:
    println("width")
case let x where x & .FlexibleTopMargin != nil:
    println("top margin")
default:
    println("no")
}

请注意,这会在匹配的第一个条件停止!所以它确实是另一种形式:

if foo & .FlexibleHeight != nil {
    println("height")
} else if foo & .FlexibleWidth != nil {
    println("width")
} else if foo & .FlexibleTopMargin != nil {
    println("top margin")
}

答案 3 :(得分:0)

我想出的另一个解决方案是:

let foo = /* .. your value to test .. */

let allCases = [UIViewAutoresizing.FlexibleHeight, UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleTopMargin]

for oneCase in allCases {
    switch oneCase & foo {

    case UIViewAutoresizing.FlexibleHeight:
        println("height")

    case UIViewAutoresizing.FlexibleWidth:
        println("width")

    case UIViewAutoresizing.FlexibleTopMargin:
        println("top")

    default:
        break
    }
}