こんにちはコーヤです。
このページでは、SwiftUIの@ObservedObjectと@EnvironmentObjectの違いをご紹介します。@ObservedObjectは別インスタンスで@EnvironmentObjectは同インスタンスのイメージです。
以下のバージョンで動作確認しています。
- Xcode 14.2
- Swift 5.7.2
実現したいこと
“Button1″と”Button2″を押した回数をカウントします。
それぞれのボタンを押した回数を
- 別々に集計するパターン(@ObservedObject)
- 一緒に集計するパターン(@EnvironmentObject)
の2パターンで実装します。
は一緒に集計するパターンで使用します。
別々に集計するパターン(@ObservedObject)
swiftファイル以下の4つでアプリを構成します。
- ContentView.swift
- View1.swift
- View2.swift
- CountClass.swift
それぞれコードは以下のとおりです。
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
View1()
Divider()
View2()
}
.font(.largeTitle)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
import SwiftUI
struct View1: View {
@ObservedObject var countClass: CountClass = CountClass()
var body: some View {
HStack(spacing: 50) {
Button("Button1") {
countClass.countUp()
}
Text("Count = \(countClass.count)")
}
}
}
struct View1_Previews: PreviewProvider {
static var previews: some View {
View1()
}
}
import SwiftUI
struct View2: View {
@ObservedObject var countClass: CountClass = CountClass()
var body: some View {
HStack(spacing: 50) {
Button("Button2") {
countClass.countUp()
}
Text("Count = \(countClass.count)")
}
}
}
struct View2_Previews: PreviewProvider {
static var previews: some View {
View2()
}
}
import Foundation
class CountClass: ObservableObject {
@Published var count: Int = 0
func countUp() {
self.count += 1
}
}
View1とView2はどちらもCountClassを@ObservedObjectとして宣言しているため、View1とView2のcountClassは別のインスタンスになります。
したがって、ボタンを押した回数も別々に集計されます。
一緒に集計するパターン(@EnvironmentObject)
同じようにswiftファイル以下の4つでアプリを構成します。
- ContentView.swift
- View1.swift
- View2.swift
- CountClass.swift
それぞれコードは以下のとおりです。
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
View1()
Divider()
View2()
}
.font(.largeTitle)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
import SwiftUI
struct View1: View {
@EnvironmentObject var countClass: CountClass
var body: some View {
HStack(spacing: 50) {
Button("Button1") {
countClass.countUp()
}
Text("Count = \(countClass.count)")
}
}
}
struct View1_Previews: PreviewProvider {
static var previews: some View {
View1()
}
}
import SwiftUI
struct View2: View {
@EnvironmentObject var countClass: CountClass
var body: some View {
HStack(spacing: 50) {
Button("Button2") {
countClass.countUp()
}
Text("Count = \(countClass.count)")
}
}
}
struct View2_Previews: PreviewProvider {
static var previews: some View {
View2()
}
}
import Foundation
class CountClass: ObservableObject {
@Published var count: Int = 0
func countUp() {
self.count += 1
}
}
View1とView2はどちらもCountClassを@EnvironmentObjectとして宣言しているため、View1とView2のcountClassは同じインスタンスになります。
したがって、ボタンを押した回数は一緒に集計されます。
@EnvironmentObjectを使用したときの注意点として、アプリをビルドする前に@mainの部分に.environmentObject()のモディファイアを加える必要があります。
下記のコードの8行目の部分を加えます。
import SwiftUI
@main
struct SampleAppApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(CountClass())
}
}
}
また、@EnvironmentObjectを使用するとXcodeのキャンパス(画面右側のプレビューするエリア)がエラーになります。
この場合はContentView_Previewsにも.environmentObject()のモディファイアを加えるとキャンパスのエラーがなくなります。
以上です。ご参考になれば幸いです。
コメント欄