What if your app could remember user choices perfectly without messy code?
Why Preference keys in iOS Swift? - Purpose & Use Cases
Imagine you want to save user settings like theme color or font size in your app. Without preference keys, you might store these settings in many places or use confusing codes to remember what each setting means.
Manually managing user settings can be slow and error-prone. You might forget which key stores what, accidentally overwrite data, or make your code messy and hard to fix later.
Preference keys give you a clear, safe way to name and access user settings. They act like labeled boxes where you store and find preferences easily, making your code cleaner and less buggy.
UserDefaults.standard.set(true, forKey: "darkMode") let dark = UserDefaults.standard.bool(forKey: "darkMode")
struct DarkModeKey: PreferenceKey {
static let defaultValue = false
}
let dark = preferences[DarkModeKey.self]With preference keys, you can safely and clearly manage user settings, making your app more reliable and easier to update.
Think of a music app remembering if you prefer dark mode or your favorite playlist. Preference keys help store these choices so the app feels personal every time you open it.
Manual settings storage is confusing and risky.
Preference keys label and organize user preferences clearly.
This leads to safer, cleaner, and easier-to-maintain code.
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
