Buttonでいいことをカウントする
いいことカウントを保存する変数を作成する
カウントするためには、そのカウントを保存したり、値を確認できたりする必要があります。そこで使用するのが、前回学んだ変数です。
いいことカウントを保存するための変数を作成して、いいことカウントボタンを押した時には、いいことカウントが1つ追加されるようにコードを次のように変更します。
struct GoodCounterView: View {
// ↓ここを追加
var goodCount = 0
var body: some View {
VStack {
Text("いいことカウンター")
.font(.largeTitle)
.bold()
.foregroundStyle(.pink)
Text("100")
.font(.system(size: 80))
Button(action: {
// 実行したい処理を記述
// ↓ここを追加
goodCount = goodCount + 1
}, label: {
Text("👍")
.font(.system(size: 100))
})
}
}
}
しかし、書き換えると、Cannot assign to property: 'self' is immutableというエラーが表示されます。これは「selfは値を変更できない(不変)状態なので、値を代入することができません」という意味で、このselfとはGoodCounterView: Viewのことになります。このGoodCounterViewはstructで定義してあり、Swiftのstructはデフォルトで自身の値を変更できないようになっています。structの説明についてはここでは省略しますが、そのままの変数では値は変更できないという程度の理解で十分です。
この値を変更するために、SwiftUIのViewでは値を更新する変数の頭に@Stateを付与する必要があります。
@Stateを学ぶ
@Stateが付くと、その値がSwiftUIによって管理され、値を更新したり、現在の値を確認できたりします。
@Stateの付いた値の変更は、SwiftUIが内部的に監視し、値が変更された際に自動的にUIを再描画してくれます。
変数に@Stateを付ける場合は次のように記述します。
@State var goodCount = 0
実際に変数goodCountに@Stateを付けると、発生していたエラーが消えることを確認できます。
@Stateの付いた変数には、private修飾子を付けることが推奨されているため、この修飾子も追加します。
@State private var goodCount = 0
privateをつけると、その値に外部からアクセスができなくなり、意図しない値の変更を防ぐことができます。
いいことカウントを画面に反映する
@Stateの付いた変数goodCountを用意し、いいことカウントボタンを押すとgoodCountが1つ追加されるようになりました。次にその値が画面に反映されるようにコードを変更します。
これまで固定の100という文字を入力していた箇所に前回学んだ\()の記法を使用して変数の値を文字列として展開します。
次のようにコードを変更してください。
struct GoodCounterView: View {
@State private var goodCount = 0
var body: some View {
VStack {
Text("いいことカウンター")
.font(.largeTitle)
.bold()
.foregroundStyle(.pink)
// ↓ここを変更
Text("\(goodCount)")
.font(.system(size: 80))
Button(action: {
goodCount = goodCount + 1
}, label: {
Text("👍")
.font(.system(size: 100))
})
}
}
}
プレビュー画面でいいことカウントボタンを押すと、いいことカウントが1つずつカウントアップできるようになりました。

これでアプリ「毎日いいことカウンター」は完成です。
プロジェクトの整理をする
アプリは完成しましたが、プロジェクトを少し整理していきます。
不要なファイルを削除する
まずは不要なファイルは削除します。
Xcodeのナビゲーターエリアの①ContentViewで右クリックを押して、表示された項目から②Deleteを選択します。

次に「Do you want to move “ContentView.swift” to the Trash?」と削除するかを確認するダイアログが表示されるのでMove to Trashを押すと削除が実行されます。

削除後に、Xcodeのナビゲーターエリアが次のようになれば完了です。

アプリ起動時に表示する画面を設定する
ContentViewの削除により、MyAppCollectionAppを表示するとCannot find 'ContentView' in scopeというエラーが表示されています。これはContentViewが見当たらないことで発生しているエラーになります。

削除したContentViewの代わりに今回作成したGoodCounterViewを設定します。
@main
struct MyAppCollectionApp: App {
var body: some Scene {
WindowGroup {
// ↓ここを変更
GoodCounterView()
}
}
}
ここで記載されている@mainは、アプリのエントリーポイントを指定するために使用されます。 @mainを使用すると、そこが起動時に最初に実行されるポイントとして認識されます。
iOSシミュレーターで動作を確認する
これまでアプリの動作はプレビュー画面で確認してきましたが、@mainのアプリのエントリーポイントとして指定したGoodCounterViewが正常に動作するか、Xcodeの実行ボタンを押して、iOS シミュレーターで実行してみましょう。

iOS シミュレーターが立ち上がり、次のように表示されれば完了です。ぜひ、その日にあったいいことを数えてみてください。自分が思っている以上に沢山のいいことがあることに気づくことができます。

まとめと次回
今回は毎日いいことカウンターアプリを作る過程で、SwiftUIでの縦並びやText、Buttonについて学びました。また、今回は詳細の説明を省略した以下のトピックについて気になった方はぜひ調べてみてください。
- アクセス修飾子
- struct
実は、今回の毎日いいことカウンターアプリのいいことカウントは永続化されていないため、アプリを起動する度にカウントは0に戻ってしまいます。永続化したい場合は、@AppStorageを変数goodCountにつけると永続化できるようになるのですが、今回の説明は省略します。チャレンジしたい方はぜひ調べてみてください。
次回はアプリ「やるのかやらないのかコイントス」を作ります。お楽しみに!

