SwiftUIでじゃんけんアプリを作ってみた!

2024/02/03に公開

対象者

  • SwiftUIに興味がある人.
  • Object思考を勉強している人.

やること/やらないこと

やること:
・引数ありのenumの使い方を学ぶ
・分岐処理を学んでみる

やらないこと:
簡単なコード書いたことある人向けなので、詳しく解説しないです。

プロジェクトの説明

今回はこんなアプリを作ります!
https://youtube.com/shorts/_909apmC8rg?feature=share

SwiftUIの入門の本で画像を使って、✊、✌️、✋を表示するのですが、好みじゃなかった...
そこで絵文字を使ってみることにしました。

TODO

  1. 新規のPJを作る.
  2. enumを使った分岐処理を書いてみる.

enumでまずは、分岐書に使う定数を用意しよう!

すべての値のコレクションを提供する型。

CaseIterable プロトコルに準拠する型は、通常、関連する値を持たない列挙型です。CaseIterable 型を使用する場合は、その型の allCases プロパティを使用して、その型のすべての case のコレクションにアクセスできます。

例えば、この例で宣言されている CompassDirection 列挙型は、CaseIterable に準拠しています。CompassDirection.allCases を使用して、ケースの数とケース自体にアクセスします。

Swiftのenumを今回使ったときは、これつけないとエラーが出る???

enum JanKen: String, CaseIterable {
    case gu = "✊"
    case choki = "✌️"
    case pa = "✋"
}

CaseIterableとは公式によると...
https://developer.apple.com/documentation/swift/caseiterable

enumの状態を扱う変数を定義する。@Stateを使って状態を更新できるようにする変数を定義します。

@State private var selectedHand = JanKen.gu.rawValue

絵文字をボタンを押すと、ランダムに切り替える処理:

VStack {
            Text(selectedHand)
                .font(.system(size: 200))
                .padding()

            Button(action: {
                selectedHand = JanKen.allCases.randomElement()?.rawValue ?? JanKen.gu.rawValue
            }) {
                Text("じゃんけんする!")
                    .frame(maxWidth: 200)
                    .frame(height: 100)
                    .background(Color.green)
                    .foregroundColor(Color.white)
            }
        }
    }

このコードでは、@State プロパティラッパーを使用して selectedHand という状態を作成しています。これは、ユーザーがボタンを押すたびに更新されます。ボタンのアクション内で、JanKen enum のすべてのケースからランダムに選択し、その結果を selectedHand に設定します。そして、Text ビューを使用して、選択された手を大きな文字で表示します。

全体のコード:

import SwiftUI

enum JanKen: String, CaseIterable {
    case gu = "✊"
    case choki = "✌️"
    case pa = "✋"
}

struct ContentView: View {
    @State private var selectedHand = JanKen.gu.rawValue

    var body: some View {
        VStack {
            Text(selectedHand)
                .font(.system(size: 200))
                .padding()

            Button(action: {
                selectedHand = JanKen.allCases.randomElement()?.rawValue ?? JanKen.gu.rawValue
            }) {
                Text("じゃんけんする!")
                    .frame(maxWidth: 200)
                    .frame(height: 100)
                    .background(Color.green)
                    .foregroundColor(Color.white)
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

?と??のところについて

このコードはSwiftのOptional ChainingとNil-Coalescing Operatorを使用しています。

JanKen.allCases.randomElement()? は、JanKen enumの全てのケースからランダムに1つ選びます。しかし、randomElement()は配列が空である可能性があるため、Optional型(JanKen?)を返します。つまり、何かしらの値があるかもしれないし、何もない(nil)かもしれないという状態です。

?はOptional Chainingと呼ばれる機能で、Optional型の値がnilでない場合のみ、その後のメソッドやプロパティ(この場合はrawValue)を呼び出します。もしOptional型の値がnilだった場合、その時点で処理は中断され、全体の結果もnilとなります。

??はNil-Coalescing Operatorと呼ばれる機能で、左側の値がnilであった場合に、右側の値(この場合はJanKen.gu.rawValue)をデフォルト値として使用します。

したがって、このコード全体の意味は「JanKenの全てのケースからランダムに1つ選び、そのrawValueを取得する。もし何らかの理由でそれが取得できなかった場合(例えば、全てのケースが何もない場合など)は、デフォルトとして"✊"(JanKen.gu.rawValue)を使用する」という意味になります。

感想

今回は、可愛いじゃんけんアプリを作ってみました。おみくじもやりたかったのですが、enumを使ってみたかったのでこっちを選びました!
色々試して、小さなアプリでSwiftUIの文法の学習をできるチュートリアルを作ってみたいですね。

Discussion