问题
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!
回答1:
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 (struct
s and enum
s).
On the other hand, @ObservedObject
should be used for reference types (class
es), 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 @ObservedObject
s 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.
回答2:
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.
来源:https://stackoverflow.com/questions/61361788/state-vs-observableobject-which-and-when