Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@State vs @ObservableObject - which and when?

I'm currently getting familiar with SwiftUI and Combine frameworks. And I'm not really getting the difference between these two approaches. When we have to keep track of some data (say, a list of tasks), we can declare a @State variable, and it's change will automatically send notification and update current view. However, it looks like it can also be done this way:

class TaskList: ObservableObject{
    //a list that's going to be modified and updated on different occasions
    @Published var list: [String]
}

class TodoListView {
    @ObservedObject var todoList = TaskList()
}

So, I missing a point - how are @State and @ObservedObject approaches different and which one is preferable under which circumstances?

Thanks!

like image 503
Alex.K Avatar asked Apr 22 '20 09:04

Alex.K


People also ask

When would you use @StateObject versus ObservedObject?

@StateObject and @ObservedObject have similar characteristics but differ in how SwiftUI manages their lifecycle. Use the state object property wrapper to ensure consistent results when the current view creates the observed object. Whenever you inject an observed object as a dependency, you can use the @ObservedObject.

What is @ObservedObject?

When using observed objects there are three key things we need to work with: the ObservableObject protocol is used with some sort of class that can store data, the @ObservedObject property wrapper is used inside a view to store an observable object instance, and the @Published property wrapper is added to any ...

What is StateObject?

A property wrapper type that instantiates an observable object.

How does @StateObject work?

If you're finding it hard to remember the distinction, try this: whenever you see “State” in a property wrapper, e.g. @State , @StateObject , @GestureState , it means “the current view owns this data.” SPONSORED In-app subscriptions are a pain. The code can be hard to write, hard to test, and full of edge cases.


2 Answers

If you mark any variables as @State in a SwiftUI View and bind them to a property inside the body of that View, the body will be recalculated whenever the @State variable changes and hence your whole View will be redrawn. Also, @State variables should serve as the single source of truth for a View. For these reasons, @State variables should only be accessed and updated from within the body of a View and hence should be declared private.

You should use @State when you are binding some user input (such as the value of a TextField or the chosen value from a Picker). @State should be used for value types (structs and enums).

On the other hand, @ObservedObject should be used for reference types (classes), since they trigger refreshing a view whenever any @Published property of the ObservableObject changes.

You should use @ObservedObject when you have some data coming in from outside your View, such as in an MVVM architecture with SwiftUI, your ViewModel should be stored as an @ObservedObject on your View.

A common mistake with @ObservedObjects is to declare and initialise them inside the View itself. This will lead to problems, since every time the @ObservedObject emits an update (one of its @Published properties gets updated), the view will be recreated - which will also create a new @ObservedObject, since it was initialised in the View itself. To avoid this problem, whenever you use @ObservedObject, you always have to inject it into the view. The iOS 14 @StateObject solves this issue.

like image 136
Dávid Pásztor Avatar answered Oct 08 '22 16:10

Dávid Pásztor


The main difference is that @State is for structs, and @ObservedObject is for classes. Both @State and @ObservedObject achieve a similar thing, of updating you when something changes.

A struct changes when some property has been mutated, which means that it gets recreated, therefore the @State is updated. A class updates @ObservedObject when a property is changed - using @Published to listen for changes. When either @State or @ObservedObject is updated, the view body gets remade.

The question you are really asking here is when to use a struct vs a class if either would work in some situations.

In your case, since TaskList is only a basic data structure and doesn't require lots of properties you want to prevent from updating the view (by using/not using @Published), you should probably use a struct with @State instead.

like image 5
George Avatar answered Oct 08 '22 15:10

George