LoginSignup
5
6

More than 1 year has passed since last update.

SwiftUIのデータ管理についてのお勉強〜ObservableObject編〜

Last updated at Posted at 2021-06-04

本記事について

SwiftUIのデータ管理についてのアウトプットやメモの共有です。
本文に載っているコードは、説明用であり、コピペでは動かないためご容赦ください。

全体像の一部

今回は、参照型のデータオブジェクトを扱う場合のProperty Wrapperについて説明します。

まず全体像としては、以下の通りです。(説明部以外は省略しています。)

スクショ

参照型のデータを扱う際、以下3つのProperty Wrapperを利用することができます。

  • @StateObject
  • @ObservedObject
  • @EnvironmentObject

これらを利用するには、まずObservableObjectプロトコルの準拠が必要です。

HomeViewModel.swift
final class HomeViewModel: ObservableObject {
    @Published var taskList: [TaskEntity] = [初期値]
}

このようにObservableObjectプロトコルを準拠した際、クラス内のプロパティに@Publishedを付与することで、taskListを監視することができます。

続いて、ObservableObjectを準拠したクラスをもとに、参照型データの扱い方について説明します。

@StateObjectについて

全体像でも記載している通り、「参照型のデータオブジェクト、View自身でデータオブジェクトを保持する」の場合は、@StateObjectを利用します。(ちなみに、iOS14からです)

以下に、サンプルコードを示します。

HomeView.Swift
struct HomeView: View {
    @StateObject private var viewModel = HomeViewModel()

    // レイアウト描画
    var body: some View {
        Button(action: {
             viewModel.taskList.append(TaskEntity(taskName: "皿洗い", taskTime: 1))
         }, label: {
             Text("追加")
         })
    //省略
    }
}

このサンプルコードの場合、viewModelが監視されているため、Buttonを押した際に、viewModelのtaskListが追加されるという実装になっています。
本来であれば、明示的な更新処理を入れる必要がありますが、SwiftUIのため必要ありません。

@ObservedObjectについて

「参照型のデータオブジェクト、親Viewから渡されるデータオブジェクトを保持する」の場合は、@ObservedObjectを利用します。

以下に、サンプルコードを示します。

TaskSettingView.swift
final class DataSource: ObservableObject {
    @Published var taskList: [TaskEntity] = [初期値]
}

struct ParentView: View {
    @StateObject private var dataSource = DataSource()

    // レイアウト描画
    var body: some View {
        ChildView(dataSource: dataSource)
    }
}

struct ChildView: View {
    @ObservedObject var dataSource: DataSource // インスタンス生成は避ける

    var body: some View {
        VStack {
            HStack {
                Button(action: {
                    dataSource.taskList.append(TaskEntity(taskName: taskName, taskTime: 3))
                }) {
                    Text("add")
                }
            }
            .padding()
        }
    }
}

このように、ParentViewで生成したdataSourceをChildViewに渡します。Childで渡されたdataSourceはObservedObjectで宣言しています。そのため、dataSourceが監視されている状態になります。

@EnvironmentObjectについて

「参照型のデータオブジェクト、アプリ全体から渡されるデータオブジェクトを保持する」の場合は、@ObservedObjectを利用します。

例えば、親Viewから一番下の階層のViewにデータを渡そうとした際、@EnvironmentObjectを利用することで階層を飛び越えてデータの監視が可能になります。

スクショ

以下に、サンプルコードを示します。

sample.swift
struct ParentView: View {
    var body: some View {
        ChiledView()
    }
}

struct ChiledView: View {
    var body: some View {
        GrandChiledView()
    }
}

struct GrandChiledView: View {
    @EnvironmentObject var dataSource: DataSource

    var body: some View {
        VStack {
            Button("add") {
                dataSource.taskList = TaskEntity(値の代入)
            }
            Text("Data: \(dataSource.taskList)")
        }
    }
}

struct GrandChildView_Previews: PreviewProvider {
    @StateObject static var dataSource = DataSource()
    static var previews: some View {
        ParentView().environmentObject(dataSource)
    }
}

親Viewに.environmentObject修飾子でデータをセットすることで、どの階層でもデータを監視することが可能となります。

終わりに

今回は以下の記事を参考に学習しました。
https://blog.personal-factory.com/2020/11/14/publish-swiftui-catalog-book/

ぜひ、参考にしてみてください。

5
6
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
5
6