본문 바로가기

학습 노트/Swift UI (2022)

24. Observable Object & Environment Object

Observable Object


 

Apple Developer Documentation

 

developer.apple.com

ObservableObject는 ObservableObject, ObservedObject, Published 셋으로 이루어져 동작한다.

  • Observable Object
    Class 프로토콜로 View에서 인스턴스의 변화를 감시 가능하다.
    값이 바뀌면 View의 업데이트가 가능해진다.
    주로 View 모델, 공유 데이터를 구성한다.
  • Observed Object
    Property Wrapper이다.
    ObservableObject를 감시한다.
  • Published
    Property Wrapper이다.
    ObservableObject에서 사용한다.
    다른 View에서 해당 속성을 감시할 수 있다.
class ViewModel: ObservableObject {
    var title = "Hello"
    @Published var list = [String]()
}

ViewModel Class는 ObservableObject 프로토콜을 채용 하고, 두 개의 속성을 가지고 있다.
하나는 일반적인 문자열 title이고, 하나는 문자열 배열 list인데,
list 속성은 '@published'를 적용했다.

ObservableObject를 채용한 객체를 Observable Object라고 부르며,
해당 프로토콜의 채용은 Published를 사용하기 위함이다.
따라서 Published를 사용하지 않는다면 ObservableObject를 채용할 필요가 없고, ObservedObject를 사용할 수 없다.

struct ObservableList: View {
    @State private var value: String = ""
    @ObservedObject var viewModel = ViewModel()

    var body: some View {
        VStack {
            Text(viewModel.title)
                .font(.largeTitle)

            Button {
                viewModel.title = "Hi"
            } label: {
                Text("Update Title")
            }
            .padding()

            HStack {
                TextField("Value", text: $value)
                    .textFieldStyle(.roundedBorder)
                    .padding()

                Button {
                    viewModel.list.insert(value, at: 0)
                    value = ""
                } label: {
                    Text("Add To List")
                }
                .padding()
            }

            List(viewModel.list, id: \.self) { item in
                Text(item)
            }
        }
    }
}

viewModel은 '@ObservedObject'를 사용한 속성이다.
'Update Title' 버튼을 누르면 viewModel의 title 속성을 업데이트하고,
'Add To List' 버튼을 누르면 TextField에 작성한 문자열을 viewModel의 list 속성에 저장한다.

List는 viewModel의 list 속성의 원소들을 차례로 나열한다.

'@Published' 속성은 list에 원소가 추가되면 이를 감지한 List가 함께 업데이트된다.
반면 'Update Title'을 눌렀을 때 변경되는 title 속성은 ObservableObject와는 관련이 없기 때문에,
이를 감지해 업데이트하지 못하고, 새롭게 list에 원소가 추가되어 View가 새로 고침 될 때 함께 업데이트된다.

 

EnvironmentObject


 

Apple Developer Documentation

 

developer.apple.com

ObservedObject보다 넓은 개념으로 여러 View에서 공통적으로 사용하는 공유 데이터를 의미한다.
관련 내용으로는 두 가지가 있다.

Environment

시스템의 공유 데이터

struct Environment_Tutorials: View {
    @Environment(\.colorScheme) var currentColorScheme
    @Environment(\.horizontalSizeClass) var currentHSize


    var body: some View {
        List {
            HStack {
                Text("Color Scheme")

                Spacer()

                Text(currentColorScheme == .dark ? "DarkMode" : "LightMode")

            }
            .padding()

            HStack {
                Text("Horizontal Size Class")

                Spacer()

                Text(currentHSize == .regular ? "Reqular" : "Compact")
            }
            .padding()
        }
    }
}

시스템에서 제공하는 공유 데이터인 colorScheme과 horizontalSizeClass를 표시하도록 구성했다.

@Environment(\.horizontalSizeClass) var currentHSize

'@Environment'에 전달하는 내용은 Keypath로 목록은 다음과 같다.

 

Apple Developer Documentation

 

developer.apple.com

시스템의 공유 데이터는 변화하는 값이기 때문에 이를 염두해 var를 사용하며,
자동으로 채워지기 때문에 초기화는 하지 않는다.

시스템의 상태에 맞게 잘 반영되는 것을 확인할 수 있다.

EnvironmentObject

커스텀 공유 데이터

struct EnvironmentObjects_Tutorials: View {
    @State private var value: String = ""
    @EnvironmentObject var viewModel: ViewModel

    var body: some View {
        VStack {
            HStack {
                TextField("Value", text: $value)
                    .textFieldStyle(.roundedBorder)
                    .padding()

                Button {
                    viewModel.list.append(value)
                    value = ""
                } label: {
                    Text("Add To List")
                }
                .padding()
            }
            .onSubmit {
                viewModel.list.append(value)
                value = ""
            }

            List(viewModel.list, id: \.self) { item in
                Text(item)
            }
        }
    }
}

이전에 생성한 ViewModel Class를 EnvironmentObject로 사용한다.
커스텀 공유 데이터는 항상 값이 존재하며, View가 생성될 때 초기화되지 않는다.
따라서 preview에서 생성자를 전달해야 할 필요가 있다.

struct EnvironmentObjects_Previews: PreviewProvider {
    static var previews: some View {
        EnvironmentObjects_Tutorials()
            .environmentObject(ViewModel())
    }
}

위와 같이 environmentObject에 ViewModel의 생성자를 전달해야 한다.
실제 개발 시에는 '~App.swift'의 @main 부분에 추가해야 한다.

'학습 노트 > Swift UI (2022)' 카테고리의 다른 글

26. List #1  (0) 2022.11.04
25. StateObject  (0) 2022.11.02
23. State & Binding  (0) 2022.10.27
22. NavigationView & TabView  (0) 2022.10.25
21. Animation  (0) 2022.10.07