SwiftUI: Do czego służy @EnvironmentObject?

Opublikowano: 18.01.2024 - tagi: SwiftUI Swift Widok Wrapper Dane

Czym jest @EnvironmentObject?

Ten wrapper służy do wymiany danych między wieloma widokami. Jest to szczególnie przydatne kiedy jeden widok składa się z wielu innych i na przykład do niektórych z nich musimy przekazać jakieś dane.

Przekazywanie danych z jednego widoku do drugiego, aż w końcu trafimy na ten, w którym te dane są potrzebne, staje się męczące. Ten problem rozwiązuje @EnvironmentObject.

Masz także gwarancję, że jeśli dane się zmienią, widok zostanie automatycznie o tym poinformowany.

Aby przejąć dane oznaczone przez @EnvironmentObject, będziesz musiał w widoku, który znajduje się wyżej w hierarchii wywołać metodę environmentObject i przekazać do niej obiekt, którym chcesz się dzielić z innymi widokami.

Najlepiej wszystko zobrazuje poniższy przykład.

Przykład

Mamy jeden model o nazwie Counter.

Trzy widoki w takiej hierarchii: ContentView -> InformationView -> CounterLabelView.

Widok CounterLabelView potrzebuje mieć dostęp do obiektu klasy Counter. Dlatego w tym widoku zostanie użyty @EnvironmentObject, aby przechwycić przesłane dane.

W widoku InformationView niepotrzebny jest obiekt klasy Counter. Zawiera on widok CounterLabelView.

W widoku głównym ContentView wywołujemy metodę environmentObject, żeby przekazać instancję klasy Counter do widoków potomnych.

Model:

import SwiftUI

class Counter: ObservableObject {
    @Published var value: Int = 0
    
    func increment() {
        value += 1
    }
    
    func decrement() {
        value -= 1
    }
    
    func reset() {
        value = 0
    }
}

Pierwszy widok:

import SwiftUI

struct CounterLabelView: View {
    @EnvironmentObject var counter: Counter
    
    var body: some View {
        Text("\(counter.value)")
            .font(.largeTitle)
    }
}

Drugi widok:

import SwiftUI

struct InformationView: View {
    var body: some View {
        VStack {
            CounterLabelView()
            Text("Click '+' to increment counter").padding()
            Text("Click '-' to decrement counter").padding()
        }
    }
}

Główny widok:

import SwiftUI

struct ContentView: View {
    @StateObject var counter = Counter()
    
    var body: some View {
        VStack {
            InformationView()
            HStack {
                Button("+") {
                    counter.increment()
                }.padding()
                
                Button("-") {
                    counter.decrement()
                }.padding()
            }
        }
        .environmentObject(counter)
    }
}