I have the following SwiftUI code:
struct TestContentView: View {
@Environment(\.verticalSizeClass) var verticalSizeClass
@Environment(\.horizontalSizeClass) var horizontalSizeClass
var body: some View {
TestView()
.ignoresSafeArea()
}
}
struct TestView: View {
@State var model:TestModel = TestModel()
var body: some View {
Text("Count \(model.counter)")
}
}
@Observable
class TestModel {
var counter:Int = 0
deinit {
print("Calling deinit on TestModel")
}
}
My problem is that TestView
and TestModel
are getting reinitialized on device autorotation, despite TestModel
being a @State
variable. This is not I want and I understand issue is I have declared size class environment variables that is causing TestView
to be reset to new value. One way to solve the problem is by moving the testModel
to superview and initializing it, but I am not sure that is always a scalable approach if you have deeper view hierarchies. What is the right approach for solving this issue, especially if one can have horizontalSizeClass
or verticalSizeClass
deep up in the view hierarchy?
Some Environment
properties make the View
re-instantiate. Developers don’t have any control over that so the solution is to use optional.
A State property always instantiates its default value when SwiftUI instantiates the view.
Instead, you can defer the creation of the object using the task(priority:_:) modifier, which is called only once when the view first appears
struct ContentView: View {
@State private var library: Library?
var body: some View {
switch library {
case .some(let library):
//@Bindable var library = library
LibraryView(library: library)
case .none:
ProgressView() //Won’t ever be visible since it happens so fast.
.task {
self.library = Library()
}
}
}
}
Delaying the creation of the observable state object ensures that unnecessary allocations of the object doesn’t happen each time SwiftUI initializes the view. Using the task(priority:_:) modifier is also an effective way to defer any other kind of work required to create the initial state of the view, such as network calls or file access.