What is PreferenceKey in SwiftUI

fatihcyln
4 min readMay 20, 2022

--

Introduction

Most common example of a preference key is actually the title in the navigation bar. When we were setting the title in a navigation view, we are actually updating the parent view from a child view.

In SwiftUI normally data flows from parent view to child view and the only way to flows back is using a binding.

When you are setting the title on a navigation view, there is no binding. We just set title as a String and it updates the parent view. It works like a charm because behind the scene it is using a preference key.

Let’s Take a Closer Look

Before using PreferenceKey, we will look how navigation title works. Because I think it is easier way to understand the concept.

There is no doubt Text is a child view of NavigationView and we set the navigation title on the child level. “Navigation Title” value is coming from the child level and it is actually changing the navigation title at NavigationView level which is a parent of Text view.

As you can see data flowed back up child to parent.

Setting Up PreferenceKey

PrefrenceKey is a protocol that we have to conforms our struct. it requires one static variable and one static function. We will review it step by step.

We have conformed PrefrenceKey protocol and put defaultValue static variable because it is required. xCode yells us because we did not determine the type of defaultValue. We can change to whatever type we want this preference key to be. We will use String in our examples.

Changed type to String and initialized with blank String. And then we will add reduce function that needed to be applied.

I think we have set up correctly because xCode is calm right now :)

In our reduce function we have inout parameter. “inout” means we are going to get this value as a parameter and we are also going to return out this String. Basically in this function we have the option of updating the current value. Let’s set up reduce function correctly to updating the current value. (if we don’t we can’t update value and we always get defaultValue which is blank String)

Thanks to nextValue() we are updating our current value. (nextValue() is a function that returns a String)

Alright, we set up everything correctly. Now we can use our PreferenceKey.

When we using it we will use two modifiers.
1- .preference(key:, value:) → modifier to update value
2- .onPreferenceChange(_ key:, perform action: ) → modifier to receive updated value

Let’s use these shiny things.

How to Use PreferenceKey

What are we going to do?
We will add second screen and that screen will show nothing but Text.
We will find out what is the purpose of defalutValue variable, .onPreferenceChange modifier and .preference modifier.
Let’s start!

I only made second screen and put it in the view hierarchy.
After that we will add .onChange modifier to anywhere in view but for sake of traceability, I will apply that modifier on NavigationView.

Well, we see a change on the view and that is “DEFAULT VALUE”.
Before moving on further lets review .onPreferenceChange modifier.
.onPreferenceChange modifier takes one parameter and that is the type of struct that conformed PreferenceKey Protocol. It returns updated value via closure so we can update our variable. (Since we didn’t set current value, it automatically uses defaultValue. Thus we are seeing “DEFAULT VALUE” in the screen.)

Let’s change current value.

We will use .preference modifier in order to update current value.
It takes two parameter, First is type of struct that conformed PreferenceKey protocol, and second is value which is determined as String.
As you can see whenever we change current value, it immediately updates PreferenceKey and we can get updated value via .onPreferenChange modifier.

Conclusion

PreferenceKey is great way to change data flow from child level to parent level.
If we have a value in child views and parent doesn’t have that value, we can pass it via PreferenceKey.

Briefly:
PreferenceKey comes in handy when we have a child that has a value that the parent does not.

--

--