iOS 응용 (SwiftUI)

[iOS - SwiftUI] @State 사용 주의사항 (뷰 업데이트)

jake-kim 2024. 9. 16. 01:41

@State 사용 케이스

  • @State는 뷰에서 접근하는 프로퍼티
struct ContentView: View {
    @State private var inputText = ""
    @State private var onAppear = false
    
    var body: some View {
        VStack {
            TextField(text: $inputText) {
                Text("placeholder...")
            }
            .onAppear {
                onAppear = true
            }
            
            if onAppear {
                Text("Appeared!")
            }
        }
    }
}
  • @State 변수는 View에서 시작해서 수정해야함 (API, viewModel이나 Interactor를 갔다와서 함수로 수정하면 변경안됨)
    • 만약 viewModel이나 비즈니스 로직을 처리하는 Interactor와 같은 곳에 갔다가 뷰 업데이트를 시켜야할 경우, 뷰에서 ObservableObject 모델을 바라보고 이 모델을 사용할 것 (@State 사용하면 변경이 뷰에 반영되지 않음)

ex) init에서 @State를 변경해도 적용되지 않음 (init은 뷰에서 접근된 함수가 아니므로)

struct ContentView: View {
    @State private var inputText = ""
    @State private var onAppear = false
    
    init() {
        inputText = "from init" // <-
    }
    
    var body: some View {
        VStack {
            TextField(text: $inputText) {
                Text("placeholder...")
            }
            .onAppear {
                onAppear = true
            }
            
            if onAppear {
                Text("Appeared!")
            }
        }
    }
}
  • init에서 초기화 했지만 "from init"이 아닌 여전히 placeholder...라고 남아있음

  • 단, 언더바를 붙여서 프로퍼티에 접근하여 State(initialValue:)로 초기화하면 가능하지만 내부 변수에 접근하는 방법이므로 이 방법을 지양
@State private var inputText = ""

init() {
    _inputText = State(initialValue: "from init")
}
  • 그렇다면 뷰가 아닌 곳에서 업데이트 할 때의 방법?
    • 뷰의 onAppear에서 수정할 것
struct ContentView: View {
    @State private var inputText = ""
    
    var body: some View {
        VStack {
            TextField(text: $inputText) {
                Text("placeholder...")
            }
            .onAppear {
                inputText = "from init" // <-
            }
        }
    }
}

 

* 읽어보면 좋은 글

- @StateObject vs @ObservedObject (#ViewModel, 뷰 상태관리)

- @StateObject 사용 주의사항 (Accessing StateObject's object without being installed on a View. This will create a new instance each time.)

- @StateObject, @EnvironmentObject, @ObservedObject 때에 맞게 사용하기