반응형

 

Hacking with Swift 사이트의 강좌 번역본입니다.

 

[원문 : https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-environmentobject-to-share-data-between-views]

 

How to use @EnvironmentObject to share data between views

 

전체 앱의 모든 뷰에서 공유되는 데이터의 경우에, SwiftUI는 @EnvironmentObject를 제공합니다. 이것은 필요한 곳 어디에서든 모델 데이터를 공유 하며, 데이터가 변경될때 뷰가 자동적으로 업데이트를 유지하는 것을 보장합니다.

 

@EnvironmentObject가 똑똑하게, 많은 뷰에서 @ObservedObject를 사용하는 더 간단한 방법이라고 생각하세요. 뷰 A에서 데이터를 만들고나서, 뷰 B에 전달하고, 뷰 C에 전달하고, 마지막으로 사용하기 전에 뷰 D로 전달하는 대신에, 뷰에서 만들고 environment에 넣어서 뷰 B, C, D에서 자동으로 사용할 수 있습니다.

 

주의: Environment 객체는 반드시 조상(ancestor) 뷰에서 제공되야 합니다 - SwiftUI가 environment 객체에서 올바른 타입을 찾지 못하는 경우에 크래쉬가 날것입니다. 이는 미리보기에서도 마찬가지이므로, 주의해야 합니다.

 

예를 들자면, 다음은 사용자 설정을 저장하는 observable 객체 있습니다.

class UserSettings: ObservableObject {
    @Published var score = 0
}

 

그렇습니다, 하나의 값만 저장하지만, 괜찮습니다 - 중요한 것은 값이 변경할때 @Published 프로퍼티 래퍼(wrapper)가 그 값을 사용하는 모든 뷰가 갱신되는 것을 보장할 것입니다. 

 

사용자 설정(User settings)은 앱 어디에서든지 공유하고자 하는 합리적인 데이터이므로 더 이상 직접 동기화 처리 할 필요가 없습니다.

 

따라서, 앱을 처음 실행할때 UserSettings의 인스턴스를 만들것이므로 공유된 인스턴스는 앱의 어디에서든 사용할 수 있습니다.

 

SceneDelegate.swift를 열어본 경우에 scene(_:willConnectTo:options:) 메소드 내부에서 다음에 오는 줄을 찾을 수 있을 것입니다.

window.rootViewController = UIHostingController(rootView: ContentView())

 

초기 컨텐츠 뷰를 만들고 화면에 표시합니다. 이곳은 우리가 만들었던 environment 객체를 전달해야 하는 곳이므로, SwiftUI는 ContentView 내부에서 사용할 수 있지만, 모든 다른 뷰에서도 사용할 수 있습니다.

 

첫번째, SceneDelegate의 프로퍼티로 다음을 추가하세요.

var settings = UserSettings() 

 

settings 인스턴스를 만들고, 안전하게 저장합니다. 이제 보여줬던 코드의 2번째 줄로 돌아가서 2번째 줄을 변경하므로 다음과 같이, settings 프로퍼티를 environment 객체로  ContentView 안으로 전달합니다.

window.rootViewController = UIHostingController(rootView: ContentView().environmentObject(settings))

 

이게 완료되고, 공유된 UserSettings 인스턴스는 컨텐츠 뷰에서 사용가능하고 모든 다른뷰에서 가져오거나 표시할 수 있습니다. 해야할 일은 다음과 같이, @EnvironmentObject 프로퍼티 래퍼(wrapper)를 사용해서 프로퍼티를 만드는 것입니다.

@EnvironmentObject var settings: UserSettings

 

environment로부터 자동적으로 읽을 것이기 때문에, 기본 값으로 초기화될 필요가 없습니다. 

 

따라서, 점수 설정을 증가하는 ConentView 구조체를 만들 수 있고, 심지어는 점수 설정을 보여주는 DetailView를 나타낼수 있으며, UserSettings의 로컬 인스턴스를 생성하거나 전달할 필요가 없습니다 - 그것은 항상 envrionment를 사용합니다. 

 

그렇게 만들수 있는 코드는 다음과 같습니다.

struct ContentView: View {
    @EnvironmentObject var settings: UserSettings

    var body: some View {
        NavigationView {
            VStack {
                // A button that writes to the environment settings
                Button(action: {
                    self.settings.score += 1
                }) {
                    Text("Increase Score")
                }

                NavigationLink(destination: DetailView()) {
                    Text("Show Detail View")
                }
            }
        }
    }
}

struct DetailView: View {
    @EnvironmentObject var settings: UserSettings

    var body: some View {
        // A text view that reads from the environment settings
        Text("Score: \(settings.score)")
    }
}

 

environment에 객체를 넣으면 상위 레벨 뷰나 10 레벨 아래에 있는 뷰에서 즉시 사용할 수 있습니다 - 중요하지 않습니다. 가장 중요한 것은, 어떤 뷰에서 environment를 바꿀때, 모든 뷰는 자동으로 갱신되므로 동기 상태를 유지합니다.

 

보다시피, Scene delegate에 있는 UserSettings 인스턴스를 2개의 뷰에 있는 settings 프로퍼티와 명시적으로 연결할 필요가 없습니다 - SwiftUI는 자동적으로 envirionment에 있는 UserSettings 인스턴스가 있는 것을 파악하므로, 그것을 사용합니다.

 

경고: 뷰는 현재 존재하는 하나의 environment 객체만 의존하기에, 사용할 몇가지 예제 설정을 제공하기 위해 미리보기 코드도 업데이트해야 합니다. 예를들어, 미리보기에서 ContentView().environmentObject(UserSettings()) 같은 것을 사용하면 됩니다.

반응형
Posted by 까칠코더
,