データを複数のViewで共有する
Published by @SoNiceInfo at 6/24/2020
データを複数のViewで共有するには変数を使います。
更新情報
iOS 14で@StateObject
が発表されました。@ObservedObject
のインスタンスはViewが描画されるたびに再生成されます。@StateObject
のインスタンスはViewの状態に関わらず維持されるという特徴があります。
導入
変数を使うには以下の3つの方法があります。
@State
変数を@Binding
する@ObservableObject
をView毎に渡す@EnvironmentObject
を利用する
@Binding
, @Published
を使うことでデータの変更はすべてのViewに反映されます。@State
変数を@Binding
する
変数を使いたい子Viewの中で@Binding
で宣言し、子Viewを呼び出すときにBinding
して($をつけて)渡します。
//
// ContentView.swift
//
import SwiftUI
struct ContentView: View {
@State var name: String = ""
var body: some View {
VStack {
Text("ContentView: ") + Text(name)
InputView(name: $name)
}
}
}
struct InputView: View {
@Binding var name: String
var body: some View {
VStack {
TextField("Placeholder", text: $name)
.padding()
.border(Color.green, width: CGFloat(2))
ResultView(name: $name)
}
}
}
struct ResultView: View {
@Binding var name: String
var body: some View {
HStack {
Text("ResultView: ")
TextField("Placeholder", text: $name)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
@ObservedObject
をView毎に渡す
ObservableObject
としてModelを定義します。
親Viewで@ObservedObject
としてインスタンスを作成します。
子Viewで@ObservedObject
として宣言した場合には、Viewの引数として渡します。
//
// ContentView.swift
//
import SwiftUI
class ViewModel: ObservableObject {
@Published var name = ""
}
struct ContentView: View {
@ObservedObject var vm = ViewModel()
var body: some View {
VStack {
Text("ContentView: ") + Text(vm.name)
InputView(vm: vm)
}
}
}
struct InputView: View {
@ObservedObject var vm: ViewModel
var body: some View {
VStack {
TextField("Placeholder", text: $vm.name)
.padding()
.border(Color.green, width: CGFloat(2))
ResultView(vm: vm)
}
}
}
struct ResultView: View {
@ObservedObject var vm: ViewModel
var body: some View {
HStack {
Text("ResultView: ")
TextField("Placeholder", text: $vm.name)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
@EnvironmentObject
を利用する
変数をすべてのViewで使いたいときには@EnvironmentObject
を利用します。
ポイントはSceneDelegate.swift
にenvironmentObjectを使うことを明示することです。 iOS14の場合WindowGroup
に明示します。
iOS 13対応
//
// SceneDelegate.swift
//
import UIKit
import SwiftUI
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Create the SwiftUI view that provides the window contents.
// 大事!!
let contentView = ContentView().environmentObject(ViewModel())
...
}
}
iOS 14対応
import SwiftUI
@main
struct iOS14App: App {
var body: some Scene {
WindowGroup {
ContentView().environmentObject(ViewModel())
}
}
}
共通
//
// ContentView.swift
//
import SwiftUI
class ViewModel: ObservableObject {
@Published var name = ""
}
struct ContentView: View {
@EnvironmentObject var vm : ViewModel
var body: some View {
VStack {
Text("ContentView: ") + Text(vm.name)
InputView()
}
}
}
struct InputView: View {
@EnvironmentObject var vm : ViewModel
var body: some View {
VStack {
TextField("Placeholder", text: $vm.name)
.padding()
.border(Color.green, width: CGFloat(2))
ResultView()
}
}
}
struct ResultView: View {
@EnvironmentObject var vm : ViewModel
var body: some View {
HStack {
Text("ResultView: ")
TextField("Placeholder", text: $vm.name)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}