I am using LazyVStack inside a ScrollView. I understand that lazy views are rendered only when they come into view. However, I haven’t heard much about memory deallocation.
I observed that in iOS 18 and later, when scrolling up, the bottom-most views are deallocated from memory, whereas in iOS 17, they are not (Example 1).
Additionally, I noticed a similar behavior when switching views using a switch. When switching views by pressing a button, the view was intermittently deinitialized. (Example 2).
Example 1)
struct ContentView: View {
var body: some View {
ScrollView {
LazyVStack {
ForEach(0..<40) { index in
CellView(index: index)
}
}
}
.padding()
}
}
struct CellView: View {
let index: Int
@StateObject var viewModel = CellViewModel()
var body: some View {
Rectangle()
.fill(Color.accentColor)
.frame(width: 300, height: 300)
.overlay {
Text("\(index)")
}
.onAppear {
viewModel.index = index
}
}
}
class CellViewModel: ObservableObject {
@Published var index = 0
init() {
print("init")
}
deinit {
print("\(index) deinit")
}
}
#Preview {
ContentView()
}
Example 2
struct ContentView: View {
@State var index = 0
var body: some View {
LazyVStack {
Button(action: {
if index > 5 {
index = 0
} else {
index += 1
}
}) {
Text("plus index")
}
MidCellView(index: index)
}
.padding()
}
}
struct MidCellView: View {
let index: Int
var body: some View {
switch index {
case 1:
CellView(index: 1)
case 2:
CellView(index: 2)
case 3:
CellView(index: 3)
case 4:
CellView(index: 4)
default:
CellView(index: 0)
}
}
}
struct CellView: View {
let index: Int
@StateObject var viewModel = CellViewModel()
var body: some View {
Rectangle()
.fill(Color.accentColor)
.frame(width: 300, height: 300)
.overlay {
Text("\(index)")
}
.onAppear {
viewModel.index = index
}
}
}
class CellViewModel: ObservableObject {
@Published var index = 0
init() {
print("init")
}
deinit {
print("\(index) deinit")
}
}
--------------------
init
init
init
init
init
2 deinit
3 deinit
4 deinit
init