Swift 2.0では、Optionの型が変わりました。 あたらしく導入された OptionSetType についてちょっと見てみました。
OptionSetTypeとは
最近、Swift1.2の既存プロジェクトのSwift2.0対応を少しずつ始めたんですが、UIUserNotificationType の option 設定でコンパイルエラーが発生。 こんな感じのコードを書いていたんですが、「Binary operator '|' cannot be applied to two UIUserNotificationType operands」というエラーが表示されていました。
let types : UIUserNotificationType = UIUserNotificationType.Badge | UIUserNotificationType.Alert | UIUserNotificationType.Sound let settins : UIUserNotificationSettings = UIUserNotificationSettings(forTypes: types, categories: nil) UIApplication.sharedApplication().registerUserNotificationSettings(settins)
また、こちらのUIView の animateWithDurationでも同様のエラーがでていました。
UIView.animateWithDuration(1.0, 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 for `NS_OPTIONS` imported from Objective-C protocol RawOptionSetType : _RawOptionSetType, BitwiseOperationsType, NilLiteralConvertible { }
上のUIUserNotificationTypeのコードはこう修正したら大丈夫でした。
let types : UIUserNotificationType = [UIUserNotificationType.Badge, UIUserNotificationType.Alert, UIUserNotificationType.Sound] let settins : UIUserNotificationSettings = UIUserNotificationSettings(forTypes: types, categories: nil) UIApplication.sharedApplication().registerUserNotificationSettings(settins)
また、UIView の animateWithDurationはこんな感じです。
UIView.animateWithDuration(1.0, 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の構造体を作ってみます。
struct 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 a1 : FoodOptions = FoodOptions.Fruits 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の集合の関係性の確認ができます。
a3.contains(FoodOptions.Tomato) // true a4.isSupersetOf(FoodOptions.RedOnes) // false a4.isSubsetOf(FoodOptions.RedOnes) // true
Optionに対する追加や削除も可能です。
a3.insert(FoodOptions.Potato) a4.remove(FoodOptions.Apple)
Swiftでは、Objective-CにくらべてEnumが拡張されて便利になりましたが、このOptionSetTypeもうまく使うといろいろと便利そうですね。 構造体なので、いろいろとメソッドを追加してさらに便利にできるのもよいところです。
これから使いこなしてみようかと思います。