8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

SwiftAdvent Calendar 2022

Day 11

associated values抜きでのenumの比較をスマートにしたい

Last updated at Posted at 2022-12-10

概要

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で記述していますが、正直もっと良い方法がないかとモヤモヤしています。
みなさんはどう書いていますでしょうか?もっと良い書き方があったらコメントで教えてください!!

8
3
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?