반응형

SwiftUI에서 많이 하는 실수 - View struct 내부에 일반 프로퍼티로 상태를 저장하려는 실수

 

SwiftUI의 View는 struct(값 타입) 입니다.
그래서 일반 저장 프로퍼티는 렌더링 사이에 쉽게 초기화되며,
“상태 유지” 목적에 사용할 수 없습니다.
상태를 유지하고 싶다면 @State, @StateObject, @ObservedObject 등을 사용해야 합니다.


1. 문제 원인

  • UIKit의 UIViewController처럼 “인스턴스 하나가 계속 살아있다”고 착각
  • var count = 0와 같은 저장 프로퍼티에 상태를 넣어도 될 거라고 생각
  • 값 타입의 재생성/복사 개념을 잘 모름

2. 나타나는 증상

  • 버튼을 눌러도 카운터가 1만 늘고, 이후 다시 0으로 돌아간 것처럼 보임
  • NavigationStack/TabView 안에서 화면 전환 후 돌아오면 값이 초기화
  • init이 자주 호출되며, 내부 값이 매번 새로 설정됨

3. 잘못된 코드 예시

struct CounterView: View {
    // ❌ 상태를 일반 저장 프로퍼티로 선언
    var count = 0

    var body: some View {
        VStack {
            Text("Count: \(count)")
            Button("증가") {
                // 컴파일은 되지만, 다음 렌더링 때 count는 다시 0
                count += 1
            }
        }
    }
}

이 코드는 버튼을 눌러도 화면상의 숫자가 변하지 않거나,

한 번만 변하고 다시 원래대로 돌아가는 것처럼 보일 수 있습니다.


4. 올바른 코드 예시

struct CounterView: View {
    // ✅ View가 소유하는 상태는 @State
    @State private var count = 0

    var body: some View {
        VStack {
            Text("Count: \(count)")
            Button("증가") {
                count += 1     // ✅ 상태 변경 → View 리렌더링
            }
        }
    }
}

또는, ViewModel로 분리하는 경우:

final class CounterViewModel: ObservableObject {
    @Published var count: Int = 0
}

struct CounterView2: View {
    @StateObject private var viewModel = CounterViewModel()

    var body: some View {
        VStack {
            Text("Count: \(viewModel.count)")
            Button("증가") {
                viewModel.count += 1
            }
        }
    }
}

5. 정리 및 팁

  • “렌더링 사이에 유지되어야 하는 값인가?” → 그렇다면 State 계열을 사용해야 합니다.
  • 일반 저장 프로퍼티는
    • 상수 레이아웃 값
    • Color, Font, spacing, 상수 텍스트 등
    • DI로 주입받은 UseCase/Service 같은 상태가 아닌 값에 사용하는 것이 안전합니다.
반응형
Posted by 까칠코더
,