
SwiftUI Cookbook
By :

SwiftUI 2.0 introduced the LazyHStack
and LazyVStack
components. These components are used in a similar way to regular HStack
and VStack
components but offer the advantage of lazy loading. Lazy components are loaded just before the item becomes visible on the device's screen during a device scroll, therefore reducing latency.
We will create an app that uses LazyHStack
and LazyVStack
and observe how it works.
Let's create a new SwiftUI app called LazyStacks
:
LazyStacks
in the Product Name field and select SwiftUI App from the Life Cycle field.We will implement a LazyHStack
and LazyVStack
view within a single SwiftUI view file by embedding both in a VStack
component. The steps are as follows:
ContentView.swift
file to view its content in Xcode's editor pane.ListRow
SwiftUI view that will have two properties: an ID and a type. ListRow
should also print a statement showing what item is currently being initialized:struct ListRow: View { let id: Int let type: String init(id: Int, type: String){ print("Loading \(type) item \(id)") self.id = id self.type = type } var body: some View { Text("\(type) \(id)").padding() } }
Text
view with VStack
:VStack { }
VStack
component and use a .frame()
modifier to limit the view's height:ScrollView(.horizontal){ }.frame(height: 100, alignment: .center)
LazyHStack
inside the scroll view with a ForEach
view that iterates through the numbers 1
–10000
and displays them using our ListRow
view:LazyHStack { ForEach(1...10000, id:\.self){ item in ListRow(id: item, type: "Horizontal") } }
VStack
with a LazyVStack
struct that loops through numbers 1
–10000
:ScrollView { LazyVStack { ForEach(1...10000, id:\.self){ item in ListRow(id: item, type: "Vertical") } } }
Figure 2.10 – Show Debug Area
Figure 2.11 – Selecting the simulator from Xcode
Figure 2.12 – The LazyStacks app running on the simulator
LazyHStack
(located at the top). Observe how the print
statements appear in the debug area just before an item is displayed on the screen. Each item is initialized just before it is displayed.LazyVStack
. Observe how the print
statements appear in the debug area just before an item is displayed.We started this recipe by creating the ListRow
view because we wanted to clearly demonstrate the advantage of lazy loading over the regular method where all items get loaded at once. The ListRow
view has two properties: an ID and a string. We add a print
statement to the init()
function so that we can observe when each item gets initialized:
init(id: Int, type: String){ print("Loading \(type) item \(id)") self.id = id self.type = type }
The ListRow
view body presents a Text
view with the ID
and type
parameters passed to it.
Moving up to the ContentView
struct, we replace the initial Text
view in the body variable with a VStack
component. This allows us to implement both LazyHStack
and LazyVStack
within the same SwiftUI view.
We implement LazyHStack
by first wrapping it in a scroll view, then using a ForEach
struct to iterate over the range of values we want to display. For each of those values, a new ListRow
view is initialized just before it becomes visible when the user scrolls down:
ScrollView { LazyVStack { ForEach(1...10000, id:\.self){ item in ListRow(id: item, type: "Vertical") } } }
Run the app using a device emulator to view the print
statements before each item is initialized. Nothing will be printed if the app is run in live preview mode on Xcode.
Try implementing the preceding app using a regular HStack
or VStack
component and observe the performance difference. The app will be significantly slower since all the rows are initialized at once.