What’s the difference between @ObservedObject, @State, and @EnvironmentObject?
Hacking with Swift 사이트의 강좌 번역본입니다.
What’s the difference between @ObservedObject, @State, and @EnvironmentObject?
상태(State)는 모든 현대적인 앱에서 사용하지만, SwiftUI는 모든 뷰가 이러한 상태(state)의 간단한 기능임을 기억하는 것이 중요합니다 - 뷰를 직접 변경하지 않지만, 대신 상태(state)를 다루고 그 결과를 지시합니다.
SwiftUI는 앱에서 상태(state)를 저장하는 몇가지 방법을 제공하지만, 그것들은 미묘하게 다르고, 해당 프레임워크를 정확히 사용하기 위해서 어떻게 다른지를 이해하는 것이 중요합니다.
모든 상태(state) 예제에서 다음과 같이 @State를 사용해서 프로퍼티를 만들었습니다.
struct ContentView: View {
@State private var score = 0
// more code
}
뷰 내부에 프로퍼티를 만들지만, SwiftUI에게 메모리를 관리하도록 요청하기 위해서 @State 프로퍼티 래퍼(wrapper)를 사용합니다. 이것은 중요합니다: 모든 뷰는 구조체이며, 이는 변경될 수 없다는 것을 의미하고, 게임에서 점수를 1 추가할 수 없다면 대단한 게임이 아닙니다.
따라서 @State 프로퍼티를 만들때, SwiftUI에게 제어를 넘김으로써 뷰가 존재하는 한 메모리에 영구적으로 남았습니다. 상태(state)가 변경될때, SwiftUI는 마지막 변경사항으로 뷰를 자동으로 다시로딩하는 것을 알고 있기에 새로운 정보를 반영할 수 있습니다.
@State는 특정 뷰에 속해있는 간단한 프로퍼티들에 좋고, 뷰의 바깥에서는 결코 사용되지 않으므로, 결과적으로 뷰를 벗어나지 않도록 특별히 설계된 상태(state) 같은 생각을 강조하기 위해서, 해당 프로퍼티들을 private가 되도록 표시하는 것은 중요합니다.
What is @ObservedObject?
좀 더 복잡한 프로퍼티들(여러개의 프로퍼티와 메소드가 있거나, 여러개의 뷰에서 공유될 수 있는 사용자정의 타입을 사용하고자 할때)은 대신 @ObservedObject를 사용해야 합니다.
이것은 문자열이나 정수형 같은 간단한 로컬 프로퍼티보다는 외부 참조 타입을 사용한다는 점을 제외하면 @State와 매우 비슷합니다. 스스로 관리해야할 책임이 있는 데이터를 제외하고는, 뷰가 데이터에 따라 변경될 것이라고 말합니다 - 해당 클래스에 대한 인스턴스를 만들고 자체 프로퍼티들을 만들어야 합니다.
@ObservedObject를 사용하는 타입은 ObservableObject 프로토콜을 준수해야 합니다. observable 객체에서 프로퍼티들을 만들때 각 프로퍼티를 변경하면 강제로 뷰를 갱신할지 안할지를 결정해야 합니다.
observed 객체에 대해 중요한 데이터가 변경되었음을 뷰에게 알리는 몇가지 방법이 있지만, 가장 쉬운 방법은 @Published 프로퍼티 래퍼(wrapper)를 사용하는 것입니다. 더 많은 컨트롤이 필요한 경우에, Combine 프로토콜에서 사용자정의 publishers를 사용할 수 있지만, 실제로 거의 드뭅니다.
경고: 객체가 변경되었음을 알리는 사용자정의 publisher를 사용할때, 반드시 메인 스레드에서 처리해야 합니다.
What is @EnvironmentObject?
해당 프로퍼티가 변경될때 뷰를 자동으로 갱신하는 타입의 간단한 프로퍼티를 @State로 선언하는 방법과, 해당 프로퍼티가 변경될때 뷰를 갱신하거나 하지 않을수 있는 외부 타입의 프로퍼티를 @ObservedObject로 선언하는 방법을 보았습니다. 이러한 2가지 모두 뷰에서 설정해야 하지만, @ObservedObject는 다른 뷰에서 공유될 수 있습니다.
사용가능한 프로퍼티의 3번째 타입은, @EnvironmentObject 입니다. 이것은 앱 자체적으로 뷰에서 사용가능하도록 만드는 값입니다 - 원하는 경우에 모든 뷰에서 읽을 수 있는 공유된 데이터 입니다. 따라서, 앱에 있는 중요한 모델 데이터를 모든 뷰에서 읽어야하는 경우, 뷰에서 뷰로 전달하거나 모든 뷰에서 바로 사용할 수 잇는 environment에 넣습니다.
앱 많은 데이터를 주변으로 전달해야 할때 @EnvironmentObject 덕분에 엄청 편리하다 생각합니다. 모든 뷰가 동일한 모델을 가리키기 때문에, 하나의 뷰가 모델을 변경하는 경우 모든 뷰는 즉시 업데이트합니다 - 앱의 다른 부분에서 동기화되지 않을 위험은 없습니다.
Summing up the differences
- 하나의 뷰에 속해 있는 간단한 프로퍼티들에 대해 @State를 사용합니다. 그것들은 보통 private로 표시됩니다.
- 여러개의 뷰에 속해 있을수 있는 복잡한 프로퍼티들에 대해 @ObservedObject를 사용합니다. 참조타입을 사용할때마다 @ObservedObject를 상용해야 합니다.
- 공유 데이터 처럼, 앱의 다른곳에서 만들어진 프로퍼티에 대해 @EnvironmentObject를 사용합니다.
3가지 중에서 가장 유용하고 가장 일반적으로 사용되는 것이 @ObservedObject임을 알 수 있으므로, 확실하지 않는 경우에 이걸 사용하세요.