SwiftUI - Property Wrappers

김세영·2022년 3월 22일
0

SwiftUI 정리

목록 보기
3/11
post-thumbnail

@State

@frozen @propertyWrapper struct State<Value>

SwiftUI에서 값을 읽고 쓸 수 있는 Property Wrapper

Overview

  • SwiftUI는 @State로 선언한 속성을 관리
  • 값이 변경되면 값에 종속된 뷰 계층을 업데이트
  • SSOT(Single Source of Truth)이다.
  • @State 인스턴스는 값이 아니라, 값을 읽고 쓰는 수단
  • 해당 상태를 참조하면 wrappedValue 속성값이 반환
struct PlayButton: View {
    @State private var isPlaying: Bool = false
    
    var body: some View {
        Button(isPlaying ? "Pause" : "Play") {
            isPlaying.toggle()
        }
    }
}
  • 버튼의 Label이 isPlaying 값에 따라 달라지고, 동작은 isPlaying을 변경
    • 이는 모두 StatewrappedValue에 의존
  • State를 하위 뷰에 전달하면, 상위 뷰에서 변경된 State로 하위 뷰를 업데이트하지만 하위 뷰는 값을 수정 불가
    • 이를 허용하려면 @Binding을 전달
  • 뷰를 인스턴스화하는 계층에서 State를 초기화하면
    SwiftUI의 스토리지 관리와 충돌할 가능성 존재
    • State를 항상 private로 선언
    • State를 접근해야 하는 계층 중 가장 상위 뷰에 배치
    • read-only 혹은 read-write가 필요한 하위 뷰와 공유

@Binding

@frozen @propertyWrapper @dynamicMemberLookup struct Binding<Value>

SSOT가 가진 값을 읽고 쓸 수 있는 Property Wrapper

Overview

  • @Binding을 사용하여, 데이터를 갖는 프로퍼티와 데이터를 표시 및 변경하는 뷰를 연결
  • 데이터를 직접 저장하지 않고, 다른 SSOT와 연결
struct PlayButton: View {
    @Binding var isPlaying: Bool

    var body: some View {
        Button(isPlaying ? "Pause" : "Play") {
            isPlaying.toggle()
        }
    }
}

struct PlayerView: View {
    var episode: Episode
    @State private var isPlaying: Bool = false

    var body: some View {
        VStack {
            Text(episode.title)
                .foregroundStyle(isPlaying ? .primary : .secondary)
            PlayButton(isPlaying: $isPlaying)
        }
    }
}

상위 뷰인 PlayerView에서는 SSOTisPlaying 값을 @State로 선언
하위 뷰인 PlayButton에서는 SSOT를 바인딩하기 위해 @Binding으로 선언

  • PlayButton 호출 시 $가 붙는 이유는
    projectedValue를 전달해주기 때문

@Environment

@frozen @propertyWrapper struct Environment<Value>

뷰의 environment를 읽는 Property Wrapper

Overview

  • 뷰의 environment에 저장된 값을 읽기 위해 사용
  • 선언할 때 EnvironmentValues keyPath를 사용하여 읽을 값을 지정
  • 프로퍼티의 wrappedValue에서 값을 읽고, 뷰의 내용을 조정
  • 값 변경 시 SwiftUI가 이를 참조한 모든 뷰를 업데이트
@Environment(\.colorScheme) var colorScheme: ColorScheme

if colorScheme == .dark { ... }
else { ... }
  • environment 값은 읽을 수 있지만 설정은 불가
  • 시스템 설정에 따라 일부 값을 자동으로 업데이트
  • 시스템 설정이 없는 경우(for others,) 합리적인 기본값 제공
  • environment(_:_:) view modifier로 재정의 가능

@StateObject

@frozen @propertyWrapper struct StateObject<ObjectType>
    where ObjectType : ObservableObject

Observable Object를 인스턴스화하는 Property Wrapper

ObservableObject (Combine)

protocol ObservableObject: AnyObject

Object가 변경되기 전에 방출(emit)하는 Publisher이 있는 타입

  • ObservableObject@Published의 속성이 변경되기 전에 이를 방출하는 objectWillChange를 합성

Overview

  • @StateObject를 사용하여 View, App, Scene에 state object를 만듦
  • Object를 선언하는 구조체의 각 인스턴스에 대해 한 개의 인스턴스를 생성
  • ObservableObject@Published가 변경되면, SwiftUI는 해당 속성을 사용한 뷰를 자동으로 업데이트

@ObservedObject

@propertyWrapper @frozen struct ObservedObject<ObjectType> 
    where ObjectType : ObservableObject

Observable Object를 구독하고, 변경될 때마다 뷰를 무효화하는 PropertyWrapper


@EnvironmentObject

@frozen @propertyWrapper struct EnvironmentObject<ObjectType> 
    where ObjectType : ObservableObject

상위 뷰(parent or ancestor)에서 제공하는 Observable Object를 선언하기 위한 Property Wrapper

Overview

  • @ObservedObject와 마찬가지로 Observable Object가 변경될 때마다 뷰를 무효화
  • Environment Object로 프로퍼티를 설정하는 경우 environmentObject(_:)를 호출하여 상위 뷰에서 값을 제공
profile
초보 iOS 개발자입니다ㅏ

0개의 댓글