🍁
Swift: CaseIterableな列挙型をGenericsで使う
SwiftUIで列挙型(enum)を利用する際、.allCases
をForEach() {}
に突っ込みたくなることがあります。そしてさらにそのViewを複数の列挙型で使いまわしたいときもあるでしょう。そんなときは以下のようにGenericsで渡せばOKです。
enumの例
enum TimeZone: String, CaseIterable {
case morning
case afternoon
case evening
case night
}
enum Season: String, CaseIterable {
case spring
case summer
case autumn
case winter
}
genericsの例
func enumItemsPicker<E: RawRepresentable & Hashable & CaseIterable>(
selection: Binding<E>
) -> some View where E.RawValue == String, E.AllCases == Array<E> {
Picker(selection: selection) {
ForEach(E.allCases, id: \.rawValue) { item in
Text(item.rawValue).tag(item)
}
} label: {
EmptyView()
}
.pickerStyle(.menu)
}
ポイント
- プレースホルダの型に複数プロトコルを定義するときは&でつなぐ
- 今回の要件の場合は
RawRepresentable & Hashable & CaseIterable
- 今回の要件の場合は
-
.rawValue
を使いたいので、where句でプレースホルダの型.RawValue == 型
のように定義する -
.allCases
を使いたいので、where句でプレースホルダの型.AllCases == Array<プレースホルダの型>
のように定義する
利用例
struct Hoge: View {
@State var timeZone = TimeZone.morning
@State var season = Season.spring
var body: some View {
VStack {
enumItemsPicker(selection: $timeZone)
enumItemsPicker(selection: $season)
}
}
func enumItemsPicker...
}
Discussion