概要
associated valuesを持つenumを扱う際、caseのみの同値比較をしたいことがあります。
enum UIState<T> {
case idle
case loading
case success(T)
case failure(Error)
}
let state: UIState<Int> = .success(1)
// associated valuesの値は興味ない、stateがsuccessかどうかだけを確かめたい
おさらいですが、associated values抜きで比較したい場合は2種類の方法があります。
switch
文と if case
文です。
// switch
switch state {
case idle: ...
case loading: ...
case success: ...
case failure: ...
}
// if case
if case .success = state { ... }
これらの方法で解決する場合も多いのですが、switchまたはifを書かなくては比較できないので、単純にBoolの値として比較結果が欲しい場合に不便です。
// SwiftUIで表示状態を指定する場合とか...
public extension View {
func overlay<Content: View>(if condition: Bool, content: @escaping () -> Content) -> some View {
overlay(Group {
if condition {
content()
} else {
EmptyView()
}
})
}
}
List(...) {
...
}
.overlay(if: state == .loading) { // これはできない
ProgressView()
}
これを解決したい
解決案1
enum側で各caseの比較値を提供するアプローチです
extension UIState {
var isIdle: Bool {
if case .idle = self {
return true
}
return false
}
var isLoading: Bool {
if case .loading = self {
return true
}
return false
}
...
}
List(...) {
...
}
.overlay(if: state.isLoading) {
ProgressView()
}
一番シンプルで無難ですが、caseが多いと少しenum側の記述が冗長に見えます。
解決案2
enum内部に、associated valuesを取り除いたenumを定義し、比較に利用します。
extension UIState {
enum Case {
case idle
case loading
case success
case failure
}
func `is`(_ caseEnum: Case) -> Bool {
switch self {
case .idle: return caseEnum == .idle
case .loading: return caseEnum == .loading
case .success: return caseEnum == .success
case .failure: return caseEnum == .failure
}
}
}
List(...) {
...
}
.overlay(if: state.is(.loading)) {
ProgressView()
}
こちらはcaseが多くても、enum側の記述が冗長になりにくいですが、enum内部に比較用のenumを定義すること自体が冗長で微妙な気もします。
コメントお待ちしております
自分は渋々解決策1で記述していますが、正直もっと良い方法がないかとモヤモヤしています。
みなさんはどう書いていますでしょうか?もっと良い書き方があったらコメントで教えてください!!