Understanding State Object, Observed Object, and Environment Object in SwiftUI

April 4, 2025

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: