prepareForSegue での segue の identifier による分岐を Swift enum で管理する
まず初めに以下の様なString型の enum を用意する。
enum SegueIdentifier: String { case a case b }
Swift 5 以前
UIViewController
の prepareForSegue
メソッド内で segue.identifier
から enum SegueIdentifier
の作成を行う。
segue.identifier
の型は String?
なので以下の様にguard文(もしくはif let文)で unwrap する必要がある。
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { guard let identifier = segue.identifier, let segueIdentifier = SegueIdentifier(rawValue: identifier) else { return } switch segueIdentifier { case .a: // do something break case .b: // do something break } }
Swift 5.1
Swift 5.1 ではSwitch文に optional の enum
が利用できる様になったのでguard文を一部簡略化して以下の様に書ける。
SegueIdentifier(rawValue: identifier)
が nil
の場合に対応するために case .none:
が必要になる。
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { guard let identifier = segue.identifier else { return } switch SegueIdentifier(rawValue: identifier) { case .a: // do something break case .b: // do something break case .none: break } }
以下の様に case .none:
の代わりに default:
でもコンパイルは通るけど、その場合 enum
の定義が増えた際に新しい enum
の値は default
にマッチしてしまうためコンパイラによる警告が出ない。.none
を使っている場合は新しい enum
の値が記述されておらず case
が網羅されていない事をコンパイラが警告してくれるため .none
を使う方が良いと思われる。
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { guard let identifier = segue.identifier else { return } switch SegueIdentifier(rawValue: identifier) { case .a: // do something break case .b: // do something break default: break } }
Swift 5.1 + extension
Switch文が optional に対応した事で enum
が作成出来ない時(rawValue の値が不正で初期化に失敗した時)はどうせ .none
に引っかかるしわざわざnullチェックのguard文を書かなきゃいけないのは面倒だな、、という気持ちが出てきた。
segue.identifier
の型がString
ではなくString?
enum Foo: String
=protocol RawRepresentable
のイニシャライザの引数が optional を許容しない
init?(rawValue: Self.RawValue)
この2点がguard文を必須にしているため、以下の様な extension を書いて RawRepresentable
に optional な引数を許容するイニシャライザを追加してみる。
gist38ded67adef6a706b05bbaeed3c1c9ff
その結果以下の様に記述できる様になる。
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { // boilerplate has gone! switch SegueIdentifier(rawValue: segue.identifier) { case .a: // do something break case .b: // do something break case .none: break } }
extension を1つ記述するだけで全ての同様の箇所のguard文(もしくはif let文)を消去する事ができる。
ボイラープレートを減らす事ができてスッキリ。