SwiftUI Modifier: EnvironmentalModifier

Doldamul·2022년 9월 25일
0
post-thumbnail
post-custom-banner

개념

protocol EnvironmentalModifier : ViewModifier where Self.Body == Never {
    associatedtype ResolvedModifier : ViewModifier
    func resolve(in environment: EnvironmentValues) -> Self.ResolvedModifier
}

실행 직전에 environment 값으로부터 구체적 modifier를 결정하는 modifier.

EnvironmentalModifier는 실행시의 View environment 값에 따라 각기 다른 수정자(modifier)를 실행할 수 있다. bodyViewModifier의 기본구현만을 사용하는 것이 강제되므로, 사용자는 body 대신 resolve 함수에서 ViewModifier를 반환하는 구문을 구현해야 한다. SwiftUI는 수정자가 호출될 때마다 EnvironmentValues 인자 전달과 함께 resolve 함수를 실행한다.

사용 예시

사용자 정의 수정자를 사용할 경우 다음과 같은 상황이 발생할 수 있다.

struct Vivid: ViewModifier {
    let isDarkmode: Bool
    
    func body(content: Content) -> some View {
        content
            .foregroundColor(isDarkmode ? .white : .black)
            .padding()
    }
}

struct ContentView: View {
    @Environment(\.colorScheme) private var colorScheme
    
    var body: some View {
        Text("Hello World")
            .modifier(Vivid(isDarkmode: colorScheme == .dark))
            // modifier의 가독성이 떨어진다.
    }
}

EnvironmentalModifier를 사용하면 위 코드를 개선할 수 있다.

// environment 값 처리 및 인자 전달이 처리된 modifier를 반환한다.
struct VividEnvironment: EnvironmentalModifier {
    struct Vivid: ViewModifier { /*위와 동일...*/ }

    func resolve(in environment: EnvironmentValues) -> Vivid {
        let isDarkmode = environment.colorScheme == .dark
        return Vivid(isDarkmode: isDarkmode)
    }
}

// 이제 environment 프로퍼티도, 인자 전달 구문도 필요하지 않다.
struct ContentView: View {
    var body: some View {
        Text("Hello World")
            .modifier(VividEnvironment())
// resolve 함수를 호출하고 반환된 modifier를 실행한다.
    }
}

다른 사용자 정의 수정자와 마찬가지로, View 익스텐션 코드 블록 내부에 modifier(_:) 수정자를 감싼 새 수정자를 정의하여 수정자 호출문을 단순하게 만들 수 있다.

extension View {
    func vivid() -> some View {
        modifier(VividEnvironment())
    }
}

...
struct ContentView: View {
    var body: some View {
        Text("Hello World").vivid()
    }
}

참고자료

profile
덕질은 삶의 활력소다. 내가 애플을 좋아하는 이유. 재밌거덩
post-custom-banner

0개의 댓글