안녕하세요. 고고입니다.
SwiftUI로 개발을 하다보면 List와 NavigationLink로 아래와 같은 화면을 만들 때가 많습니다.
List(1...100, id: \.self) { id in
NavigationLink(destination: SecondView(id: id)) {
Text("\(id)번째 항목")
}
}
아래 코드는 FirstView에서 리스트의 항목을 하나 클릭하면 SecondView로 이동합니다.
struct FirstView: View {
var body: some View {
List(1...100, id: \.self) { id in
NavigationLink(destination: SecondView(id: id)) {
Text("\(id)번째 항목")
}
}.navigationTitle("FirstView")
}
}
class SecondViewModel: ObservableObject {
let id: Int
init(id: Int) {
self.id = id
print("init - SecondViewModel \(id)")
}
deinit {
print("deinit - SecondViewModel \(id)")
}
}
struct SecondView: View {
@ObservedObject var viewModel: SecondViewModel
let id: Int
init(id: Int) {
self.id = id
self.viewModel = SecondViewModel(id: id)
}
var body: some View {
Text("Hello World!")
.navigationTitle("\(id) SecondView")
}
}
FirstView로 들어가면 현재 화면에 보이는 16개의 SecondView의 이니셜라이저가 호출되며 SecondViewModel도 함께 생성되게 됩니다.
만약 스크롤을 내리면 추가로 화면에 표시된 SecondView가 더 생성됩니다. 이렇게 생성된 SecondView들은 FirstView를 나가기 전까지 사라지지 않습니다.
FirstView를 나가면 사라집니다.
이렇게 NavigationLink의 destination인 뷰의 생성자가 자꾸 호출되는 게 싫다면, LazyView로 감싸주면 됩니다.
import SwiftUI
struct LazyView<Content: View>: View {
let build: () -> Content
init(_ build: @autoclosure @escaping () -> Content) {
self.build = build
}
init(@ViewBuilder _ build: @escaping () -> Content) {
self.build = build
}
var body: Content {
build() // << everything is created here
}
}
struct FirstView: View {
var body: some View {
List(1...100, id: \.self) { id in
NavigationLink(destination: LazyView(SecondView(id: id))) {
Text("\(id)번째 항목")
}
}.navigationTitle("FirstView")
}
}
class SecondViewModel: ObservableObject {
let id: Int
init(id: Int) {
self.id = id
print("init - SecondViewModel \(id)")
}
deinit {
print("deinit - SecondViewModel \(id)")
}
}
struct SecondView: View {
@ObservedObject var viewModel: SecondViewModel
let id: Int
init(id: Int) {
self.id = id
self.viewModel = SecondViewModel(id: id)
}
var body: some View {
Text("Hello World!")
.navigationTitle("\(id) SecondView")
}
}
이렇게 LazyView로 감싸주니 FirstView에서 destination인 SecondView의 생성자가 호출되지 않습니다.
NavigationLink(destination: LazyView { SecondView(id: id) })
NavigationLink(destination: LazyView(SecondView(id: id)))
LazyView로 감싸면 아래처럼 리스트의 항목을 클릭해서 SecondView로 이동했을 때에만 단 하나의 SecondView가 생성됩니다.
SecondView에서 뒤로가기를 선택하면 deinit됩니다.
List 또는 ForEach로 많은 NavigationLink를 만들고, destination인 뷰의 생성자를 많이 호출하는 게 부담된다면 LazyView를 사용하는 것을 추천드립니다.
'SwiftUI' 카테고리의 다른 글
[SwiftUI] GeometryReader의 iOS 버전별 차이 (0) | 2022.08.18 |
---|---|
[SwiftUI] `ForEach(_:content:)` should only be used for *constant* data. (0) | 2021.11.25 |
[SwiftUI] Previews in Xcode 번역 (0) | 2021.11.06 |
[SwiftUI] navigationBarTitle LayoutConstraints error (0) | 2021.11.06 |
[SwiftUI] iOS 13부터 지원하기 (0) | 2021.11.04 |
댓글