とり研

iPhoneアプリ開発とかプログラミングとかの話題。

Objective-CのenumをSwiftで使うときは、値がEnumValueになるのでちょっと注意

この記事は、仙台iOS開発者勉強会(SWWDC) Advent Calendar 2014 10日目の記事です。

Objective-CのenumをSwiftで使うときのちょっとしたTips

今回の元ネタは、先日のAdvent Calendar対策もくもく会にて出た質問です。多分他にも困る人がいるのではないかと思いまして。

まず、下記のようなenumがあります。これをbridge-headerを経由して、Swiftで使います。

typedef NS_ENUM(NSUInteger, EnumValue) {
    EnumValue1 = 0x00000001,
    EnumValue2 = 0x00000002,
    EnumValue3 = 0x00000004,
    EnumValue4 = 0x00000008,
};

そして、Objective-Cのif文をそのままSwiftに移植したら、ビルドエラーになるとのことでした。

if EnumValue.Value1 & EnumValue.Value2 {
    println("これはビルドエラー")
}
// Cannot Invoke '&' with an argument list of type'(EnumValue, EnumValue)'

enumの元の値を取得するときは、"rawValue"

エラーメッセージを見ると、「EnumValueとEnumValueの&は出来ないよ」というようなことを言われています。 Objective-CならEnumValue1 もEnumValue2 も”NSUInteger"だったので &で演算ができていたのですが、Swiftに持ってくるとEnumValueになっちゃうようですね。

こんな時は、"rawValue"を使うと、元の値がとれます。

// 値出力テスト
println("EnumValue.Value1=\(EnumValue.Value1)")
println("EnumValue.Value1.rawValue=\(EnumValue.Value1.rawValue)")

// 実行結果(print)
EnumValue.Value1=(Enum Value)
EnumValue.Value1.rawValue=1

さらに、if文の書き方にも注意。

では、rawValueを使用して下記のように書くと、ビルドエラーが起きます。

if EnumValue.Value1.rawValue & EnumValue.Value2.rawValue {
    println("これもビルドエラー")
}
// Type 'UInt' does not conform to protocl 'BooleanType'

これは以前アドヴェントCalendarで取り上げた問題ですね.([ Swiftのif文の条件部は、BooleanType準拠の値しか受け付けない模様 - Qiita] )。Swiftでは、条件式の中身はBooleanTypeになっていないといけないのでした。

更に修正を加え、最終的にはこんな感じになりました。

if EnumValue.Value1.rawValue & EnumValue.Value2.rawValue != 0 {
    println("これはok")
}

終わりに

Swiftで書くと、こういう「地味にObjective-Cのソースコードを移植する」作業が発生するので、時間を取られてしまうんですよね。

なので、こういったTips記事を書いていって、調査の負担を減らして行けば、Swiftがより普及するのではないかなと思いました。

仙台iOS開発者勉強会(SWWDC) Advent Calendar 2014 - Qiita