Preference keys help you share small pieces of information inside your app easily. They let different parts of your app talk to each other without being tightly connected.
Preference keys in iOS Swift
struct MyPreferenceKey: PreferenceKey {
static var defaultValue: Int = 0
static func reduce(value: inout Int, nextValue: () -> Int) {
value += nextValue()
}
}The PreferenceKey protocol requires a defaultValue and a reduce function.
The reduce function combines multiple values from child views.
struct MaxWidthKey: PreferenceKey {
static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = max(value, nextValue())
}
}struct ColorPreferenceKey: PreferenceKey {
static var defaultValue: Color = .clear
static func reduce(value: inout Color, nextValue: () -> Color) {
value = nextValue()
}
}This example measures the width of two text views and shows the maximum width below them. It uses a preference key to pass width values up the view tree.
import SwiftUI struct MaxWidthKey: PreferenceKey { static var defaultValue: CGFloat = 0 static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { value = max(value, nextValue()) } } struct ContentView: View { @State private var maxWidth: CGFloat = 0 var body: some View { VStack { Text("Short") .background(GeometryReader { geo in Color.clear.preference(key: MaxWidthKey.self, value: geo.size.width) }) Text("A much longer text") .background(GeometryReader { geo in Color.clear.preference(key: MaxWidthKey.self, value: geo.size.width) }) Text("Max width: \(maxWidth, specifier: "%.1f")") .padding() } .onPreferenceChange(MaxWidthKey.self) { value in maxWidth = value } .padding() } }
Preference keys are great for passing data from child views to parent views.
Use GeometryReader with preference keys to measure view sizes.
The reduce method lets you combine multiple values, like finding a max or sum.
Preference keys let views share simple data up the view hierarchy.
They require a default value and a reduce function to combine values.
Commonly used with GeometryReader to pass layout info.
Practice
PreferenceKey in SwiftUI?Solution
Step 1: Understand PreferenceKey role
PreferenceKeyis designed to pass data from child views up to parent views in SwiftUI.Step 2: Differentiate from other uses
It is not for permanent storage or UI elements but for sharing layout or state info upwards.Final Answer:
To share simple data up the view hierarchy -> Option BQuick Check:
PreferenceKey = share data up [OK]
- Confusing PreferenceKey with UserDefaults
- Thinking it creates UI components
- Assuming it manages network tasks
PreferenceKey with a default value of 0 and a reduce function that sums values?Solution
Step 1: Check static defaultValue declaration
It must be a static property with explicit type:static var defaultValue: Int = 0.Step 2: Verify reduce function signature
Reduce must be static, takeinoutvalue, and add nextValue:static func reduce(value: inout Int, nextValue: () -> Int).Final Answer:
struct MyKey: PreferenceKey { static var defaultValue: Int = 0; static func reduce(value: inout Int, nextValue: () -> Int) { value += nextValue() } } -> Option DQuick Check:
Static defaultValue and reduce with inout = struct MyKey: PreferenceKey { static var defaultValue: Int = 0; static func reduce(value: inout Int, nextValue: () -> Int) { value += nextValue() } } [OK]
- Missing static keyword on defaultValue or reduce
- Using var instead of static var for defaultValue
- Incorrect reduce function parameters
struct CountKey: PreferenceKey {
static var defaultValue = 0
static func reduce(value: inout Int, nextValue: () -> Int) {
value += nextValue()
}
}
struct ContentView: View {
var body: some View {
VStack {
Text("Hello").preference(key: CountKey.self, value: 1)
Text("World").preference(key: CountKey.self, value: 2)
}
.onPreferenceChange(CountKey.self) { print($0) }
}
}Solution
Step 1: Understand preference values set
Two Text views set preferences with values 1 and 2 respectively.Step 2: Apply reduce function logic
Reduce sums values: 0 (default) + 1 + 2 = 3.Final Answer:
3 -> Option AQuick Check:
Sum of preferences = 3 [OK]
- Assuming only last value is used
- Ignoring reduce function behavior
- Confusing defaultValue with output
PreferenceKey implementation:
struct SizeKey: PreferenceKey {
static var defaultValue: CGSize = .zero
static func reduce(value: CGSize, nextValue: () -> CGSize) {
value = nextValue()
}
}Solution
Step 1: Check defaultValue declaration
defaultValue is correctly static with CGSize type.Step 2: Inspect reduce function signature
Reduce must takeinoutfor value to modify it, but here it is a value parameter.Final Answer:
reduce function must have inout parameter for value -> Option AQuick Check:
Reduce needs inout value parameter [OK]
- Forgetting inout keyword in reduce
- Changing defaultValue to non-static
- Wrong return type for nextValue
PreferenceKey. Which implementation correctly combines widths to find the maximum?Solution
Step 1: Identify correct reduce logic for max
To find maximum width, reduce must assign the max of current and next values.Step 2: Verify function signature and logic
Reduce must be static, takeinoutvalue, and usevalue = max(value, nextValue()).Final Answer:
struct MaxWidthKey: PreferenceKey { static var defaultValue: CGFloat = 0; static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { value = max(value, nextValue()) } } -> Option CQuick Check:
Use max in reduce with inout value [OK]
- Using sum (+) instead of max
- Missing inout in reduce parameter
- Using min instead of max
Ready to prove it?
Pass the test and this pattern moves unknown
