An Observed Object is created as a class when you have multiple views relying on the same data. Each piece of data can be represented as states using the (Publisher) property
First step is to create it as an Observable Object, typically our model
class Student: ObservableObject {
@Published var name: String
@Published var age: Int
init(name: String, age: Int){
self.name = name
self.age = age
}
}
Note: An object declared as an ObservableObject means that it is capable of Publishing Changes (triggering view redraws) but must be declared as the right object
var sampleStudent: Student = Student("ehan",25)
sampleStudent.age += 1
// Will not trigger a redraw, because it is created as a value object
If this is the first instance of Student being passed from Parent to child views, you must use a StateObject. To trigger refreshes we must instantiate the object as a StateObject (wrapper to an observable object)
- A StateObject represents the single source of truth of an observable object.
For example:
@StateObject var sampleStudent = Student("ehan", 25)
sampleStudent.age += 1
// Triggers redraw and refreshes screen
An EnvironmentObject allows us to instantiate an instance of an observable object and pass it from the parent view to multiple child views without explicitly passing it as a parameter.
-> Prevents prop drilling -> Easily keeps data across views consistent
For example:
struct ContentView: View {
@StateObject var student = Student(name: "E-Han", age: 25)
var body : some View {
NavigationStack {
Text("Student's age: \(student.age)")
NavigationLink("Click Me!"){
ClassView()
}
}
.environmentObject(student)
}
}
struct ClassView : View {
@EnvironmentObject var sampleStudent : Student
var body : some View {
Text("Name of student is \(sampleStudent.name)")
Button("Increment age"){
sampleStudent.age += 1
}
}
}
References: