SwiftUI

[SwiftUI] 데이터 바인딩 어노테이션 @ 이해하기

예빈 Yebeen 2024. 4. 2. 14:01
728x90
반응형

사실 개발하면서도 언제 어느 때에 써야할지 지금도 헷갈리는 State, StateObject, ObservedObject ...등등

현재 진행하는 프로젝트에서도 검색 기능을 구현할 때 ObservedObject로 썼을 때 검색창이 일회용이 되어버렸던.... 그러다가 StateObject를 만났던... 복잡하지만 확실하게 알아두는게 좋을 것 같아서 학습해본다.

 


데이터 바인딩

SwiftUI에서 데이터 바인딩은 View와 데이터 사이의 동기화라고 한다. 나는 지금 현재 MVVM 패턴을 사용하며 개발하고 있기 때문에 ViewModel을 View에 연결해서 사용할 때 꼭 필요하다.

데이터 바인딩은 사용자 인터페이스가 데이터 모델의 현재 상태를 정확하게 반영하도록 보장해준다.

사용자의 입력 또는 데이터 모델에서 변화가 생길 때 UI에 자동으로 반영할 수 있게 해주고, 자동으로 업데이트 되기 때문에 간편하다.

 

그럼 이제 몇 가지 주로 사용하는 어노테이션에 대해서 알아보자!


1. @State

State는 뷰의 내부 상태를 관리하기 위해 사용된다.

SwiftUI 뷰 코드 내부를 보면 struct, 즉 구조체이기 때문에 그냥 프로퍼티를 선언해서 값을 변경하게 되면 에러가 난다.

이 프로퍼티 값이 변경된 걸 뷰에서 업데이트할 수 있게 적용하려면 프로퍼티를 선언한 코드 앞에 @State를 붙여주면 된다.

이때 @State는 private으로 다른 뷰와는 공유되지 않는다.

 

State Apple 공식 문서

 

State | Apple Developer Documentation

A property wrapper type that can read and write a value managed by SwiftUI.

developer.apple.com

 

간단하게 코드로 보면

struct ContentView: View {
    @State private var name = "이름"
    
    var body: some View {
    	name = "yecong"
        
        Text("안녕하세요.")
        Text(name)
    }
}

 


2. @Binding

바인딩은 데이터에 직접 접근을 해야하는 경우에 사용된다.

토글 버튼이나 텍스트 필드 등 직접 접근하는 뷰에서 바인딩 값을 넣어주어야 하는데 이때 바인딩할 프로퍼티를 선언할 때는 $(프로퍼티)로 표기하면 된다.

 

Binding Apple 공식 문서

 

Binding | Apple Developer Documentation

A property wrapper type that can read and write a value owned by a source of truth.

developer.apple.com

 

간단하게 스위치로 이해해보면

struct ContentView: View {
    @State private var isOn = false
    
    var body: some View {
        Toggle(isOn: $isOn) {
            Text("스위치")
        }
    }
}

 


3. @ObservedObject와 @StateObject

두 어노테이션 모두 뷰 바인딩을 할 때 사용된다.

이 어노테이션들은 ViewModel을 View에 선언할 때 자주 쓰게 된다. 이 어노테이션을 연결해주면서 ViewModel 변화를 감지할 수 있고 View에서는 반응을 한다

ios14 이전에는 @ObservedObject만 있었고 이후부터는 @StateObject가 등장했다.

최근 프로젝트를 하다가 @ObservedObject에 문제가 생기면 @StateObject를 사용해서 문제를 해결해줬는데 사실 왜 된건지 잘 몰랐다.

이 둘의 차이점은 뭘까?

[ 데이터 변화에 대한 반응 ]

- Observed는 데이터 변화가 있으면 뷰를 처음부터 다시 생성한다.

- State는 데이터 변화가 있으면 변화가 있는 부분의 뷰만 다시 생성한다.

 

[ 생명주기 ]

- Observed는 뷰가 사라지고 다시 생성되면 인스턴스도 사라지고 다시 생성된다.

- State는 초기에 인스턴스가 생성되면 뷰가 사라지고 생성되는 것에 상관없이 유지된다.

 

[ 사용 ]

- Observed는 다루는 데이터가 달라지는 하위 뷰에서 사용한다.

- State는 데이터를 유지해야 하고 초기에 생성되는 상위 뷰에서 사용된다.

 

그래서 내 검색 화면 구현 시점으로 돌아와서 생각해보면 왜 일회용이 되어버렸는지 인지할 수 있었다. ObservedObject를 선언했을 때는 바텀 탭뷰를 이동할 때마다 뷰를 재생성하게 되는데 이렇게 무한생성을 하다 보니 검색바에서는 대.혼.란이 있었을 것이라는게 느껴졌다. 상위뷰에서 Observed로 사용하는데 뷰도 막 무한 생성에 인스턴스도 재생성되고 아주 복잡하고 정신없었을 듯.. 그에 비하면 StateObject는 말 그대로 데이터 변화가 있는 곳만 다시 생성하기 때문에 뷰 전체에 영향을 미치지 않고 딱 Textfield 부분과 검색 결과 부분만 재생성되는 것이므로 기존에 검색한 결과 유지도 되고 아주 최적의 검색바를 만들 수 있었던 것!

 

ObservedObject Apple 공식 문서

 

ObservedObject | Apple Developer Documentation

A property wrapper type that subscribes to an observable object and invalidates a view whenever the observable object changes.

developer.apple.com

 

StateObject Apple 공식 문서

 

StateObject | Apple Developer Documentation

A property wrapper type that instantiates an observable object.

developer.apple.com

4. @EnvironmentObject

@EnvironmentObject는 앱의 여러 부분에 접근해야 하는 공유 데이터에 사용된다. 이 어노테이션을 사용하게 되면 데이터 소스를 뷰 계층의 깊은 곳으로 쉽게 전달할 수 있다.

특히 여러 레벨에 걸쳐서 사용되는 데이터에 적합하다.

 


이 강력하고도 중요한 어노테이션을 제대로 이해하고 학습할 수 있는 시간이었다. 물론 개발하면서 깨달음을 얻은 부분이라 꼭 중요하다고 생각되어서 학습도 해보고 기록도 남긴다.

오늘의 코드레시피 끄읕!👩🏻‍🍳

728x90