SwiftUI는 선언형 UI 프레임워크로, 자동으로 UI를 업데이트해주는 장점이 있지만,
성능을 고려하지 않으면 불필요한 Re-Rendering이 발생할 수 있습니다.
이번 글에서는 SwiftUI의 성능을 최적화하는 5가지 방법을 소개합니다.
1. @State의 과도한 사용 줄이기
잘못된 예제
@State가 변경될 때마다 전체 body가 다시 평가되므로 성능 저하가 발생할 수 있습니다.
struct CounterView: View {
@State private var count = 0
var body: some View {
VStack {
Text("Count: \(count)")
Button("Increment") {
count += 1
}
}
}
}
문제점: count가 변경될 때마다 body가 전체적으로 다시 평가됩니다.
개선 방법
뷰를 별도의 struct로 분리하면, count 변경 시 최소한의 렌더링만 수행됩니다.
struct ParentView: View {
@State private var count = 0
var body: some View {
VStack {
Button("Increment") {
count += 1
}
CounterLabel(count: count)
}
}
}
struct CounterLabel: View {
let count: Int
var body: some View {
Text("Count: \(count)")
}
}
개선점: CounterLabel이 독립적인 뷰로 분리되어 불필요한 재평가를 방지할 수 있습니다.
2. EquatableView 활용하기
SwiftUI는 기본적으로 값이 변경될 때마다 body를 다시 호출하지만, EquatableView를 사용하면 값이 동일할 경우 재평가를 방지할 수 있습니다.
예제 코드
struct CustomText: View, Equatable {
var text: String
var body: some View {
Text(text)
}
static func == (lhs: CustomText, rhs: CustomText) -> Bool {
return lhs.text == rhs.text
}
}
효과: 값이 변경되지 않는 한 렌더링이 다시 일어나지 않습니다.
3. @ViewBuilder를 활용한 뷰 분리
뷰 내부에서 if, switch 문을 사용할 경우, SwiftUI는 매번 body를 평가하면서 전체 UI를 다시 구성할 수 있습니다.
잘못된 예제
struct ContentView: View {
@State private var isOn = false
var body: some View {
VStack {
Toggle("Switch", isOn: $isOn)
if isOn {
Text("On 상태입니다")
} else {
Text("Off 상태입니다")
}
}
}
}
문제점: if문 내부의 모든 뷰가 매번 재평가됩니다.
개선 방법
struct ContentView: View {
@State private var isOn = false
var body: some View {
VStack {
Toggle("Switch", isOn: $isOn)
DisplayText(isOn: isOn)
}
}
}
struct DisplayText: View {
let isOn: Bool
var body: some View {
Text(isOn ? "On 상태입니다" : "Off 상태입니다")
}
}
개선점: DisplayText를 별도 뷰로 분리하여 불필요한 렌더링을 방지할 수 있습니다.
4. LazyVStack 및 LazyHStack 사용하기
VStack과 HStack은 모든 자식 뷰를 한 번에 렌더링하지만, LazyVStack과 LazyHStack은 필요한 부분만 렌더링하여 성능을 향상시킵니다.
예제 코드
struct ListView: View {
let items = Array(1...1000)
var body: some View {
ScrollView {
LazyVStack {
ForEach(items, id: \ .self) { item in
Text("Item \(item)")
}
}
}
}
}
📌 효과: 필요한 항목만 로드하여 성능을 최적화할 수 있습니다.
5. PreferenceKey를 활용하여 부모-자식 간 데이터 전달 최소화
@Binding이나 @EnvironmentObject를 사용할 경우 전체 뷰가 다시 렌더링될 수 있습니다. 이를 방지하려면 PreferenceKey를 사용하여 데이터 전달을 최소화할 수 있습니다.
예제 코드
struct ContentView: View {
@State private var title = "Default Title"
var body: some View {
VStack {
Text(title)
.onPreferenceChange(TitlePreferenceKey.self) { newValue in
title = newValue
}
ChildView()
}
}
}
struct ChildView: View {
var body: some View {
Text("Tap Me")
.preference(key: TitlePreferenceKey.self, value: "Updated Title")
}
}
struct TitlePreferenceKey: PreferenceKey {
static var defaultValue: String = ""
static func reduce(value: inout String, nextValue: () -> String) {
value = nextValue()
}
}
효과: 부모 뷰 전체가 다시 렌더링되지 않고, 필요한 값만 갱신됩니다.
결론
SwiftUI의 성능을 최적화하려면 불필요한 뷰 렌더링을 최소화하는 것이 중요합니다.
'클라이언트' 카테고리의 다른 글
[Swift] Swift6의 주요 내용 (0) | 2025.02.15 |
---|---|
[Swift] Swift Concurrency 개념과 사용법 간단 정리 (0) | 2025.02.15 |
[SwiftUI] SwiftUI View 렌더링 순서 관련 정리 (0) | 2025.02.15 |
[SwiftUI] SDWebImage SwiftUI로 WebP 이미지 보여주기 (0) | 2025.02.15 |
Date 특정 월 - 주 별 시작과 끝 날짜 쌍 목록 구성하기 (0) | 2022.04.27 |