Swift 2.0では、Optionの型が変わりました。
あたらしく導入された OptionSetType についてちょっと見てみました。
OptionSetTypeとは
最近、Swift1.2の既存プロジェクトのSwift2.0対応を少しずつ始めたんですが、UIUserNotificationType の option 設定でコンパイルエラーが発生。
こんな感じのコードを書いていたんですが、「Binary operator ‘|’ cannot be applied to two UIUserNotificationType operands」というエラーが表示されていました。
UIUserNotificationType.Badge |
UIUserNotificationType.Alert |
UIUserNotificationType.Sound
let settins : UIUserNotificationSettings = UIUserNotificationSettings(forTypes: types, categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settins)
また、こちらのUIView の animateWithDurationでも同様のエラーがでていました。
delay: 0.0,
options: UIViewAnimationOptions.CurveEaseIn |
UIViewAnimationOptions.Autoreverse,
animations: {
// animation
},
completion: { finishe in
// completion
}
)
Bit演算できないってどういうこと?と思って調べてみると、UIUserNotificationType や UIViewAnimationOptions の型がSwift1.2ではRawOptionSetTypeだったのに、Swift 2.0では OptionSetTypeに変更になっていました。
RawOptionSetTypeはBit演算可能(BitwiseOperationsType)ですが、OptionSetTypeは違うので、bit演算でエラーがでていたんですね。
ヘッダーファイルを見ると、Swift1.2まで使われていたRawOptionSetTypeはNS_OPTIONSをそのままインポートしたものでしたが、OptionSetTypeはそれを大幅改良したもののようです。
protocol RawOptionSetType : _RawOptionSetType, BitwiseOperationsType, NilLiteralConvertible {
}
上のUIUserNotificationTypeのコードはこう修正したら大丈夫でした。
[UIUserNotificationType.Badge,
UIUserNotificationType.Alert,
UIUserNotificationType.Sound]
let settins : UIUserNotificationSettings = UIUserNotificationSettings(forTypes: types, categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settins)
また、UIView の animateWithDurationはこんな感じです。
delay: 0.0,
options: [UIViewAnimationOptions.CurveEaseIn, UIViewAnimationOptions.Autoreverse],
animations: {
// animation
},
completion: { finishe in
// completion
}
)
Xcodeには、最新のSwiftに自動コンバートしてくれる機能があります。
このOptionSetTypeに関しては、自動的に変換してくれる場合もあるみたいですが、私のプロジェクトではだめだったので、大量のUIView.animateWithDurationのoptionを手動で修正しました。
OptionSetTypeのよい点
このOptionSetTypeには set的な演算子があらかじめ定義されているので、オプションの扱いが便利になりました。
たとえば、こんな感じの FoodOptionsというOptionSetTypeの構造体を作ってみます。
let rawValue: Int
init(rawValue: Int) { self.rawValue = rawValue }
static let Apple = FoodOptions(rawValue: 1)
static let Orange = FoodOptions(rawValue: 2)
static let Banana = FoodOptions(rawValue: 4)
static let Potato = FoodOptions(rawValue: 8)
static let Tomato = FoodOptions(rawValue: 16)
static let Fruits : FoodOptions = [Apple,Orange,Banana]
static let Vegetables : FoodOptions = [Potato,Tomato]
static let RedOnes : FoodOptions = [Apple,Tomato]
static let YellowOnes : FoodOptions = [Banana,Potato]
}
Apple、Orange、Banana……といった、今までと同じようなOption値を作ることもできますが、Fruitsなどのように、複数のOptionを含む状態のOptionを定義することもできます。
二つのOptionSetTypeの or演算には、 unionを使います。
同様に、and 演算には、intersect、exclusive orは、exclusiveOrを使います。
let a2 : FoodOptions = FoodOptions.RedOnes
var a3 : FoodOptions = a1.union(a2) // = Apple,Orange,Banana,Tomato
var a4 : FoodOptions = a1.intersect(a2) // = Apple
let a5 : FoodOptions = a1.exclusiveOr(a2) // = Orange,Banana,Tomato
Optionに特定のOption値が入っているかどうかは containsで調べられます。
isSupresetOfやisSubsetOfでは、setの集合の関係性の確認ができます。
a4.isSupersetOf(FoodOptions.RedOnes) // false
a4.isSubsetOf(FoodOptions.RedOnes) // true
Optionに対する追加や削除も可能です。
a4.remove(FoodOptions.Apple)
Swiftでは、Objective-CにくらべてEnumが拡張されて便利になりましたが、このOptionSetTypeもうまく使うといろいろと便利そうですね。
構造体なので、いろいろとメソッドを追加してさらに便利にできるのもよいところです。
これから使いこなしてみようかと思います。