-
Notifications
You must be signed in to change notification settings - Fork 0
PreferenceKey
SwiftUI의 PreferenceKey는 자식 뷰 → 부모 뷰로 값을 전달할 때 사용하는 메커니즘.
일반적인 @State, @Binding, Environment는 부모 → 자식 방향 데이터 흐름.
PreferenceKey는 child → ancestor 방향으로 데이터를 전달하는 메커니즘.
즉, SwiftUI의 데이터 흐름에서 예외적으로 “위로 올라가는 데이터 전달”을 수행하는 도구. 🔁
SwiftUI의 기본 구조는 단방향 데이터 흐름.
Parent
↓
Child
하지만 특정 상황에서 Child의 정보를 Parent가 알아야 하는 경우의 존재.
예시:
- 자식 뷰의 size
- 자식 뷰의 position
- 자식 뷰들의 custom value
구조 예시:
Parent
└ ChildView
Parent가 필요로 할 수 있는 정보의 예시:
-
ChildView의 height -
ChildView의 frame - 여러 child들의 값
이때 사용하는 도구가 PreferenceKey.
PreferenceKey는 protocol.
protocol PreferenceKey {
associatedtype Value
static var defaultValue: Value { get }
static func reduce(value: inout Value, nextValue: () -> Value)
}각 요소의 의미:
| 요소 | 설명 |
|---|---|
Value |
전달할 데이터 타입 |
defaultValue |
기본값 |
reduce |
여러 child가 있을 때 값을 합치는 방법 |
struct TitlePreferenceKey: PreferenceKey {
static var defaultValue: String = ""
static func reduce(value: inout String, nextValue: () -> String) {
value = nextValue()
}
}struct ChildView: View {
var body: some View {
Text("Hello")
.preference(key: TitlePreferenceKey.self, value: "Hello Title")
}
}핵심 API:
.preference(key:value:)
이 메서드의 역할은 값을 부모에게 전달하는 동작.
struct ParentView: View {
@State private var title: String = ""
var body: some View {
VStack {
Text(title)
ChildView()
}
.onPreferenceChange(TitlePreferenceKey.self) { value in
title = value
}
}
}데이터 ��름 구조:
ChildView
│
.preference()
│
▼
PreferenceKey
│
▼
Parent .onPreferenceChange
Child가 여러 개 존재할 수 있기 때문.
Parent
├ Child1
├ Child2
└ Child3
각 child가 값을 전달하는 구조.
- Child1 → value1
- Child2 → value2
- Child3 → value3
reduce에서 여러 값을 어떻게 합칠지 결정하는 로직의 정의.
예시:
마지막 값 사용
value = nextValue()배열로 수집
value.append(nextValue())최대값 선택
value = max(value, nextValue())SwiftUI에서 PreferenceKey의 대표적인 사용 사례는 child view size 측정 패턴.
PreferenceKey 정의
struct SizePreferenceKey: PreferenceKey {
static var defaultValue: CGSize = .zero
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
value = nextValue()
}
}Child 측 코드:
.background(
GeometryReader { geo in
Color.clear
.preference(
key: SizePreferenceKey.self,
value: geo.size
)
}
)Parent 측 코드:
.onPreferenceChange(SizePreferenceKey.self) { size in
print(size)
}이 구조는 SwiftUI에서 매우 널리 사용되는 패턴.
PreferenceKey의 확장 개념인 AnchorPreference의 존재.
뷰의 위치 정보를 anchor 형태로 전달하는 기능.
대표 사용 사례:
- sticky header 구현
- scroll tracking
- view overlay positioning
관련 API:
.anchorPreference(key:value:transform:)
SwiftUI의 다양한 layout 트릭에서 활용되는 핵심 기술.
다음 상황에서 PreferenceKey 사용의 적합성.
| 상황 | 해결 방법 |
|---|---|
| child size 필요 | PreferenceKey |
| child frame 필요 | PreferenceKey |
| scroll offset 추적 | PreferenceKey |
| 여러 child 값 collect | PreferenceKey |
| 특징 | Environment | PreferenceKey |
|---|---|---|
| 방향 | Parent → Child | Child → Parent |
| 목적 | 설정 전달 | 결과 전달 |
| 사용 | theme, locale | size, position |
SwiftUI 내부 컴포넌트에서도 PreferenceKey 활용의 존재.
대표 사례:
NavigationTitleToolbar-
Listrow background -
ScrollViewoffset tracking
즉 SwiftUI layout 시스템의 핵심 기술 중 하나.
PreferenceKey = SwiftUI에서 Child → Parent 방향으로 값을 전달하기 위한 공식적인 메커니즘
TagEditor에서 sheet의 detents 최적화
PushNotificationView의 푸시 알람 기록 UNDO 과정-V1
PushNotificationView의 푸시 알람 기록 UNDO 과정-V2
Publishing 상태 변환에 따른 에러 해결하기
iOS 17 이하에서 모달의 isPresented 관리하기
LPMetadataProvider로 웹페이지 썸네일 가져오기
Todo-리마인더-구현-트러블슈팅
iOS 17 .searchable 포커싱 이슈 해결기
TodoListView 헤더 트러블슈팅-스크롤 조정
TodoListView 헤더 트러블슈팅-내비게이션바