7
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SwiftUIのプロパティラッパー

Posted at

プロパティラッパーとは

プロパティの値の読み書きに対して特定の処理を自動で適用する仕組みのことを言います。
今回はSwiftUIでよく使うプロパティラッパーを4つ紹介します。

今回紹介するプロパティラッパー

  1. @State
  2. @Binding
  3. @ObservedObject
  4. @StateObject

1,@State

@Stateは画面の中で変わるデータを入れておく特別な箱のことです。

@State の特徴

  • ビュー内のローカルな状態を管理する
  • @State の値が変わると SwiftUI が自動で画面を更新
  • 親ビューには渡せない(ローカル専用)

例えばゲームをやっているときにスコアが増えたりHPが減ったりすると思います。このような画面内のデータを管理しています。

スコア管理処理
import SwiftUI

struct CounterView: View {
    @State private var count = 0  // 変わる数を入れる箱(最初は0)

    var body: some View {
        VStack {
            Text("スコア: \(count)") // スコアを表示
                .font(.largeTitle)

            Button("+1する") {
                count += 1  // ボタンを押したら count を増やす
            }
            .padding()
            .font(.title)
        }
    }
}

上記のコードのように初期値として0を入れた箱を作ってボタンを押すごとに1が追加されていきます。
普通の変数 (var) を使うと、ボタンを押しても画面が更新されません。
@State を使うと、SwiftUIが「値が変わった!」と気づいて、画面を自動で書き換えてくれます。

2,@Binding

@Bindingは親ビューが持つデータを子ビューで変更できるようにするための仕組みです。

@Binding の特徴

  • 親ビューのデータを子ビューで操作できる
  • @State などの 保持されているデータをバインドして操作可能
  • @Binding だけではデータを保持できない(@State などと組み合わせて使う)

今回はテレビとリモコンを例にして説明します。
テレビの音量はリモコンがないと設定できないものがほとんどだと思います。そのためリモコンで操作することによってテレビの音量を変更します。これを実際のコードに落とし込むと以下のようになります。

テレビの音声を調整する処理

import SwiftUI

// 親ビューテレビ
struct ParentView: View {
    @State private var volume = 10  // 現状の音量(データ)

    var body: some View {
        VStack {
            Text("テレビの音量: \(volume)") // 親ビューで音量を表示
                .font(.largeTitle)

            RemoteView(volume: $volume) // 子ビューに音量を渡す
        }
    }
}

// 子ビューリモコン
struct RemoteView: View {
    @Binding var volume: Int  // 親の volume を参照するための @Binding

    var body: some View {
        HStack {
            Button("🔈 -") { volume -= 1 }  // 音量を下げるボタン
            Button("🔊 +") { volume += 1 }  // 音量を上げるボタン
        }
        .font(.largeTitle)
        .padding()
    }
}


このように親Viewで表示させているものをを子Viewで変更させるときに@Bindingを使います。

3,@ObservedObject

@ObservedObject は、外からもらったデータを監視するための仕組みです。

@ObservedObject の特徴

  • 親から渡された ObservableObject を監視する
  • データが変更されると、自動でビューを更新
  • @StateObject ではなく、@ObservedObject は親ビューで作られたデータを使うために使用する

今回はサウナを例にします。サウナは温度が上がりすぎてもダメだし下がりすぎてもダメですよね。なので定期的に温度を監視する必要があります。
これをSwiftのアプリに落とし込むと以下のようになります。

サウナの温度を調整する処理

import SwiftUI

// サウナの温度を管理するクラス
class Sauna: ObservableObject {
    @Published var temperature = 80  // サウナの温度(デフォルト80℃)
}

// サウナスタッフサウナの温度を調整するビュー
struct StaffView: View {
    @ObservedObject var sauna: Sauna  // サウナを監視

    var body: some View {
        VStack {
            Text("サウナの温度: \(sauna.temperature)℃")
                .font(.largeTitle)

            HStack {
                Button("加熱") { sauna.temperature += 5 }  // 5℃上げる
                Button("冷却") { sauna.temperature -= 5 }  // 5下げる
            }
            .padding()
            .font(.title)
        }
    }
}

このコードのように@ObservedObjectを使う SwiftUI の View が ObservableObject の変更を監視しています。

4,@StateObject

@StateObjectは、アプリの中で長く使うデータを管理するための箱のことです。

@StateObject の特徴

  • 親ビューのデータを子ビューで操作できる
  • @State などの 保持されているデータをバインドして操作可能
  • @Stateは画面内でデータを管理しますが、画面を更新すると消えてしまいます@StateObjectでは画面を更新されてもデータが残る

ポケモンを例にすると画面を更新するたびにポケモンのレベルがリセットされると困りますよね。1度上がったレベルというのはデータとして保持される必要があります。そういった必要な情報を管理するために@StateObjectが必要になります。

@StateObjectを使ったポケモンアプリ

import SwiftUI

// ポケモンのデータを管理するクラス
class Pet: ObservableObject {
    @Published var level = 1  // ポケモンのレベル(最初は1)
}

// ポケモンバック親ビュー
struct HomeView: View {
    @StateObject private var myPoke = Pokemon() // ポケモンの箱

    var body: some View {
        VStack {
            Text("ポケモンのレベル: \(myPoke.level)")
                .font(.largeTitle)

            Button("育てる") {
                myPoke.level += 1  // レベルアップ
            }
            .padding()
            .font(.title)
        }
    }
}


もしポケモンのレベルを@Stateで管理すると画面上でしか管理できません。@StateObjectを使ってポケモンのレベルアップがデータとして保存されます。

まとめ

私はこれまでUIkitで開発を進めていることが多く、UIkitではView間のデータ管理の処理を複雑に感じていました。プロパティラッパーを活用するとそれが容易にでき、非常に便利だと思っています。まだSwiftUIを本格的に初めて日が浅く、これから覚えることがたくさんあるのでその都度ここにアウトプットできればなと思います。

7
11
0

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
7
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?