Working with .preference / .onPreferenceChange in SwiftUI I would sometimes wonder “why is this value not passed up”. I reproduced my feeling-puzzled with this example:
struct ExamplePreferenceKey: PreferenceKey {
static let defaultValue: Int = 0
static func reduce(value: inout Int, nextValue: () -> Int) {
let nextValue = nextValue()
print("»reduce»", value, "<-", nextValue)
value = nextValue
}
}
struct ContentView: View {
var body: some View {
ZStack {
Color.red
.preference(
key: ExamplePreferenceKey.self,
value: 123
)
.onPreferenceChange(ExamplePreferenceKey.self) { size in
print("»", size)
}
VStack {
// if true { // <-- Uncomment the if statement
Text("yo")
// }
}
}
.onPreferenceChange(ExamplePreferenceKey.self) { size in
print("»»", size)
}
}
}
This works and you’ll see the preference changing on the element and also on the outer ZStack. But uncomment the if statement and the outer ZStack will not have the value anymore and you can see that another preference (assuming it’s a default value) will overwrite the existing value:
»reduce» 123 <- 0
»» 0
» 123
Of course, knowing that this can happen, one could implement the reduce function accordingly.
But still: Why does this happen? What’s going on here? Why does including the if-statement in a sibling View cause the appearance of another ‘default’ preference value?