I would like to use a struct
instead of a class
as a state for my View
, and as you may know, ObservableObject
is a protocol only classes can conform to.
Do I have to wrap my struct in a ViewModel
or some other similar type of object ? What happens if I don't ?
A sample on what that looks like now :
import Foundation
import SwiftUI
struct Object3D {
var x : Int
var y : Int
var z : Int
var visible : Bool
}
struct NumberView<Number : Strideable> : View {
var label : String
@State var number : Number
var body : some View {
HStack {
TextField(
self.label,
value: self.$number,
formatter: NumberFormatter()
)
Stepper("", value: self.$number)
.labelsHidden()
}
}
}
struct ObjectInspector : View {
@State var object : Object3D
var body : some View {
VStack {
Form {
Toggle("Visible", isOn: $object.visible)
}
Divider()
Form {
HStack {
NumberView(label: "X:", number: object.x)
NumberView(label: "Y:", number: object.y)
NumberView(label: "Z:", number: object.z)
}
}
}
.padding()
}
}
struct ObjectInspector_Previews: PreviewProvider {
static var previews: some View {
ObjectInspector(object: Object3D(x: 0, y: 0, z: 0, visible: true))
}
}
You don't have to use @ObservedObject
to ensure that updates to your model object are updating your view.
If you want to use a struct
as your model object, you can use @State
and your view will be updated correctly whenever your @State
struct
is updated.
There are lots of different property wrappers that you can use to update your SwiftUI views whenever your model object is updated. You can use both value and reference types as your model objects, however, depending on your choice, you have to use different property wrappers.
@State
can only be used on value types and @State
properties can only be updated from inside the view itself (hence they must be private
).
@ObservedObject
(and all other ...Object property wrappers, such as @EnvironmentObject
and @StateObject
) can only be used with classes that conform to ObservableObject
. If you want to be able to update your model objects from both inside and outside your view, you must use an ObservableObject
conformant type with the appropriate property wrapper, you cannot use @State
in this case.
So think about what sources your model objects can be updated from (only from user input captured directly inside your View
or from outside the view as well - such as from other views or from the network), whether you need value or reference semantics and make the appropriate choice for your data model accordingly.
For more information on the differences between @ObservedObject
and @StateObject
, see What is the difference between ObservedObject and StateObject in SwiftUI.