ObservableObject in SwiftUI

ObservableObject is a protocol in SwiftUI that enables a class to be observed for changes. When an object conforms to ObservableObject, it can broadcast changes to its properties so that SwiftUI views can update themselves automatically when these properties change.

Key Features of ObservableObject:

  • Broadcast Changes: When properties of an ObservableObject change, views observing the object will automatically update.
  • @Published Properties: Use the @Published property wrapper to mark properties that should trigger view updates when they change.

How to Use ObservableObject:

Define a Class Conforming to ObservableObject:

Create a class and conform it to the ObservableObject protocol. Use @Published to mark properties that will be observed.

class Person: ObservableObject {
    @Published var age: Int = 0
}

Create and Use an ObservableObject in a SwiftUI View:

Initialize your ObservableObject in a SwiftUI view and observe it using @StateObject.

import SwiftUI
struct ContentView: View {
    // creating instance of the class
    @StateObject var person: Person = Person()
    
    var body: some View {
        
        Stepper("Age: \(person.age)", value: $person.age)
            .padding()
        
    }
}

#Preview {
    ContentView()
}

// createing class
class Person: ObservableObject {
    @Published var age: Int = 0
}

We need to use @StateObject to create an instance of an ObservableObject within a view. There are other ways to use an ObservableObject too. Like using @EnvironmentObject or @ObservedObject. You can get a clear idea of the difference between StateObject, EnvironmentObject, and ObserbedObject from this article.

To get a clear idea of how ObservableObject works, we will create a child view and observer for changes:

import SwiftUI
struct ContentView: View {

    
    @StateObject var person: Person = Person()
    
    var body: some View {
        
        Stepper("Age: \(person.age)", value: $person.age)
            .padding()
        
        ChildView(person: person)
        
    }
}

#Preview {
    ContentView()
}

 
class Person: ObservableObject {
    @Published var age: Int = 0
}


struct ChildView: View {
    @ObservedObject var person: Person
    var body: some View {
        Text("Your age is \(person.age)")
    }
}

If we change the value in the parent view, the value in the child view also gets updated.

@Published Properties:

When we mark the properties of a ObservableObject with @Published, any changes to these properties will notify SwiftUI to re-render the views and update its values.

Using ObservableObject with EnvironmentObject:

If you want your ObservableObject to be available throughout your app, use @EnvironmentObject.

  1. Initialize and Inject into the Environment:
import SwiftUI

@main
struct AppName: App {
    
    @StateObject private var person = Person()

    var body: some Scene {
        WindowGroup {
            ContentView()
            // injecting to the environment
                .environmentObject(person)     
        }
    }
}
// createing class. You may use diffrent file. 
class Person: ObservableObject {
    @Published var age: Int = 0
}

Now we can use this object anywhere without reinitializing it.

import SwiftUI
struct ContentView: View {
    // using environment object
    @EnvironmentObject var person: Person
    
    var body: some View {
        
        Stepper("Age: \(person.age)", value: $person.age)
            .padding()
        
    }
}

#Preview {
    ContentView()
        .environmentObject(Person())
}

Note: We have to inject the object manually into the preview itself since it acts standalone and can’t see our injection at the top level. Otherwise preview will crash.

Leave a Reply