Posted at

SwiftにおけるSwitchまとめ

More than 3 years have passed since last update.

swiftのswitchは色々便利なのでまとめてみました。

他の言語のswitchでもその特徴はある、というものもあると思いますがとりあえず特徴を列挙していきます。


swiftのswitchの特徴


breakするためにbreakを書く必要がない

Objective-Cではcase文から抜けるためにbreakを記述していましたが、swiftではbreakを書く必要がありません。

これで「breakを書かなかったから次のcase文まで実行されてしまった」というミスがなくなりました。

しかし意図的に次のcase文も実行したい、という場合はfallthroughを使います。


fallthrough

let num = 0

var str = ""
switch num {
case 0:
str += "0"
fallthrough
default:
str += "です"
print(str)
}
=> 0です


様々な型の指定が可能

Objective-Cでは条件式の部分は整数値、と決まっていましたが、Swiftでは様々な型で利用可能です。

なので次のようなコードを書くことが可能です。


例1:Double型


double

let double = 2.4

switch double {
case 0.0..<10.0:
print("1桁")
default:
print("その他")
}

ちなみにswiftでは範囲演算子が存在し、

「0...9」であれば9を含み,

「0..<9」であれば9を含まないというものになります。


例2:enum


enum

enum Drink {

case Coffee, Tea
}

let drink = Drink.Coffee
switch drink {
case .Coffee:
print("coffee")
case .Tea:
print("tea")
}


基本的にswiftのswitchではdefaultは必須ですが(書かないとswitch must be exhaustiveエラーが出る)、今回はenumで定義している値を網羅しているので書く必要はありません。

ちなみにこの状態でDrinkにWaterなど新たな値を追加すると、Waterはどのcase文にも当てはまらなくなってしまうのでXcodeに怒られます。

※このコードは簡易的に作ったものなのでそのままコピペするとSwitch condition evaluates to a constantという警告が出ます。


例3:Class


Class

var vc = UIApplication.sharedApplication().keyWindow?.rootViewController

while let presented = vc?.presentedViewController {
vc = presented
}
switch vc {
case is UIAlertController:
print("UIAlertController")
default:
print("別のクラス")
}

現在最前面に出ているVCに応じてswitchを使って処理分けをしようとするとこんなかんじになると思います。


複数の条件を列挙できる

「,」で区切れば列挙することができます。

let club = "baseball"

switch club {
case "baseball", "basketball":
print("運動部")
default:
print(club)
}


where句で細かい指定が可能

追加で条件を指定したい時に使います。

let score = (70, 60)

switch score {
case (let english, let math) where english == 100 && math == 100:
print("満点!素晴らしい!")
case (let english, let math) where english >= 70 && math >= 70:
print("英語\(english)点、数学\(math)点。\n両方合格")
case (let english, _) where english >= 70:
print("とりあえず英語\(english)点取れてるから数学ができてなくても許す")
default:
print("もっと頑張れ")
}

そしてこのようにswitchの条件の中でタプルを使用することができます。


関連値によるマッチングができる

以下の例で言う関連値はcodeですね。

enum Status {

case Success
case Error(code: Int)
}

let status = Status.Error(code: 400)
switch status {
case .Success:
print("成功")
case .Error(code: 400):
print("Bad Request")
case .Error(code: 500):
print("Internal Server Error")
default:
print("何かのエラー")
}


switchのパターンマッチングの正体

内部的に~=演算子で比較されているようです。

ではここで~=演算子をオーバーロードしてみます。

※あくまでもswitchを理解するために作ったものであり、実用性やswitchを使うことの妥当性は度外視しています。

「画面がタップされた時にそのPointを取得し、それが所定のRectの中に入っているかどうかを判定したい」という場合は~=演算子を次のようにオーバーロードします。

func ~= (rect:CGRect, point:CGPoint) -> Bool

{
return ((rect.minX...rect.minX + rect.width) ~= point.x) && ((rect.minY...rect.minY + rect.height) ~= point.y)
}

使う時はこんなかんじ。

let point = (タップしたpoint)

let rect = (所定のrect)
switch point {
case rect:
print("rectの中だよ!")
default:
print("rectの外だよ!")
}


その他Tips


  • defaultを書く場合はswitch文の一番最後に書く必要があります。default書いてからcase文を書くと怒られます。

  • case, defaultの中には何かしら書いてないと怒られます。何も処理を行いたくない時はbreakなどを入れておく。


最後に

switch文はかなり幅広く使えます。

うまく使えばネストを浅くできてリファクタリングにもなるので是非活用してみてください。


参考文献

開発のプロが教える Swift標準ガイドブック