SwiftUI 有幾個 Stack 元件前加上了 Lazy,例如 LazyVStack、LazyHStack、LazyVGrid…等。加上 Lazy 的排版元件可以在需要載入內容並且選染畫面的時候才開始處理,而沒有 Lazy 的元件則是將所有需要載入與選染內容的工作在一開始就全部完成。當要顯示的資料筆數過多的時候,使用 Lazy 元件會減少記憶體使用與大幅提昇效能。
Lazy 元件需搭配 ScrollView 元件一起使用,以 LazyVStack 為例,在 ContentView 中加上下面這個結構,用來觀察到底在畫面出現時事先生成了多少個元件。
struct MyView: View {
let i: Int
init(_ i: Int) {
self.i = i
print(i)
}
var body: some View {
Text(i, format: .number)
.padding()
}
}
ScrollView
然後執行下面這段程式碼。這時可以觀察到在 Xcode 右下方的 Preview 面板中大約只印出 10~15 左右的數字,表示此時只產生了 10 幾個 MyView 元件(這個數字每個人都不一樣,反正會比一個畫面能顯示的數量再多一點)。之後當使用者捲動捲軸時,才會依需要再產生。
// ✅
ScrollView {
LazyVStack {
ForEach(0..<200) { i in
MyView(i)
}
}
}
如果將 LazyVStack 改成 VStack 結果就不一樣了,會一開始就印出 199,代表一次就產生了 200 個 MyView 元件,雖然實際上一個畫面不可能顯示這麼多資料,但此時還是要載入全部資料進記憶體並且開始進行排版,系統效能會被嚴重拖慢。
// ❌
ScrollView {
VStack {
ForEach(0..<200) { i in
MyView(i)
}
}
}
List
List 元件需要配合 LazyVStack 嗎?答案是不用。List 元件本身就內建記憶體管理,只有在需要的時候才載入元件與進行排版,例如下面這段程式碼。預覽或執行時會在 Xcode 右下角的 Preview 面板中看到只產生 10 幾個 MyView 元件,捲動捲軸時才會依需要產生其餘的 MyView。然後千萬別在 ForEach 外面加上 LazyVStack,加上後在一開始就會建立所有 200 個 MyView 元件,效能反而變差了。
// ✅
List {
// LazyVStack {
ForEach(1..<200) { i in
VStack {
MyView(i)
}
}
// }
}
如果只有 List 而沒有 ForEach,例如下面這段程式碼,此時使用 VStack 或 LazyVStack 都可以。
// ✅
List(1..<200) { i in
VStack {
MyView(i)
}
}
但如果沒有 VStack 或 LazyVStack 時,就會一次產生 200 個元件。
// ❌
List(1..<200) { i in
MyView(i)
}
■ Xcode 測試版本:15.4 與 16.0 beta 5