본문 바로가기

iOS/SwiftUI

[SwiftUI 기초] @Environment, Environment Values로 View의 계층적인 환경 관리하기

Environment values

Share data throughout a view hierarchy using the enviroment.

스위프트UI의 View들은 Environment 프로퍼티 래퍼를 통해서 환경으로부터 읽은 confiugration 정보에 반응하여 스스로의 UI를 구성할 수 있다. 이러한 environement 정보는 Container로부터 계층적으로 내려가서 하위 View들에게 전해진다. 따라서 Envrionment values를 이용하면 전체적인 뷰 계층의 환경을 조정할 수 있다.

@Environment

A property wrapper that reads a value from a view’s environment

@frozen @propertyWrapper struct Environment<Value>

Enrionment 프로퍼티 래퍼는 뷰의 환경에 저장되어 있는 값을 읽을 수 있도록 해준다.

아래와 같은 형태로, EnvironmenValues값에 키패스를 통해 접근할 수 있도록 한다.

@Environment(\\.colorScheme) var colorScheme: ColorScheme

Environment Values의 종류

이미 EnvironmentValues에는 다양한 key들이 존재한다. 예를 들어 calendar, local, timezone과 같은 시간, 위치 정보부터 managedObjectContext와 같이 Core Data의 context를 제공하는 key까지 다양하다.

 

개발자 문서에 따르면 다음과 같이 분류되어 있다.

 

Accessibility

Actions: dismiss(뷰의 dismiss), openURL(window presentation), refresh, …

Authentication

Controls and input: controlSize, keyboardShortcut, …

Display characteristics: colorScheme, displayScale

Global Object: calendar, local, …

Scrolling: isScrollEnabled, …

State: editMode, isFocused, …

Text styles: font, lineLimit, lineSpacing, …

View attributes: backgroundMaterial

Widget

Custom EnvironmentKey 만들기

EnvironmentKey Protocol : environment에 있는 값에 접근하는 Key

Custom Envirionment Values를 만들기 위해서는 EnvironmentValues에 새로운 property를 extension하고, defaultValue를 할당하면 된다.

private struct MyEnvironmentKey: EnvironmentKey {
    static let defaultValue: String = "Default value"
}

EnvironmentValues를 extension하여 아래와 같이 연산 프로퍼티로 만들어주고, 위에서 만든 Key struct를 아래처럼 EnvironmentValues Dictionary의 key 값으로 넣어주면 된다.

extension EnvironmentValues {
    var myCustomValue: String {
        get { self[MyEnvironmentKey.self] }
        set { self[MyEnvironmentKey.self] = newValue }
    }
}

.environment() modifier를 사용하면 keyPath를 통해 EnvironmentValues를 할당할 수 있다.

func environment<V>(
    _ keyPath: WritableKeyPath<EnvironmentValues, V>,
    _ value: V
) -> some View

MyView()
    .environment(\\.myCustomValue, "Another string")

.environment()메서드를 한번 더 Wrapping해서, Custom Modifier로 만들어 사용 가능하다.

extension View {
    func myCustomValue(_ myCustomValue: String) -> some View {
        environment(\\.myCustomValue, myCustomValue)
    }
}

MyView()
    .myCustomValue("Another string")

특정 뷰 내부, 또는 뷰의 자손에서 Envrionment 값을 참조하고 싶다면 @Environment 래퍼를 사용할 수 있다.

struct MyView: View {
    @Environment(\\.myCustomValue) var customValue: String

    var body: some View {
        Text(customValue) // Displays "Another string".
    }
}