前段
Swift 4.2 の CaseIterable
の allCaeses
を使って enum の case の一覧や個数が取得可能になり随分便利になった。
表題の enum の index の取得について、まず Int
型の場合は以下の様に CaseIterable
を使わなくても rawValue
を使ってシンプルに取得出来る。
enum Animal: Int { case dog case cat case rabbit } let index: Int = Animal.cat.rawValue
CaseIterable を使って case の index を取得する
では Int
型の enum が様々な事情により以下の様に定義されている場合どうだろう。
enum Animal: Int { case dog = 1 case cat = 3 case rabbit = 4 }
この場合 CaseIterable
を適用すれば下記の様に allCases
のコレクションを使って index の取得が出来る。
firstIndex(of:)
が返す型は Optional の Int?
型だが .cat
は確実に allCases
に存在しているので Optional を unwrap している。
enum Animal: Int, CaseIterable { case dog = 1 case cat = 3 case rabbit = 4 } let index: Int = Animal.allCases.firstIndex(of: .cat)!
rawValue
に依存しないで index が取得出来る様になったので型も Int
型に縛られる事がなくなる。
例えば String
だったり
enum Animal: String, CaseIterable { case dog = "イヌ" case cat = "ネコ" case rabbit = "うさぎ" } let index: Int = Animal.allCases.firstIndex(of: .cat)!
型自体を外してしまって RawRepresentable
プロトコルに適合しなくしても良い。
enum Animal: CaseIterable { case dog case cat case rabbit } let index: Int = Animal.allCases.firstIndex(of: .cat)!
Extension にする
色々汎用化を試みて CaseIterable
の Extension とする実装に落ち着いた。
これを Swift のプロジェクトに入れておけば CaseIterable
な enum から一発で index を取得する事が出来る。
extension Hashable where Self : CaseIterable { var index: Self.AllCases.Index { return type(of: self).allCases.firstIndex(of: self)! } }
以下の様に簡単に書けるので UITableView
周りで section と row から IndexPath
を作る時などに便利に使ってる。
enum Animal: CaseIterable { case dog case cat case rabbit } let index: Int = Animal.cat.index
ソースファイル
https://gist.github.com/Koze/59a1b31c45217b9f46c11737ba905534#file-caseiterable-index-swift
*1:毎回 allCases を呼ぶためリソースの無駄がある事は頭の隅に置いておくべきかも。それをシビアに気にしなくちゃいけない様な巨大な enum はあまり無いとは思うけど。