Persisting Toggle States with UserDefaults: Setting Up Visibility
In this demo, you’ll learn how to use UserDefaults to preserve settings on an app called JoyJotter. It’s a funny app where users can save jokes to cheer them up whenever they feel down. Start by opening the starter project for this lesson. Build and run the project.
The app displays basic data over three tabs: the first one contains a list of jokes organized by category. The second tab displays the user’s selected favorite jokes, and the last tab has two app-related settings. This is where you’ll start your journey.
The Settings tab has a toggle
to show or hide the favorite tab. Switch the toggle off, and check if the favorite tab disappears. Stop and run your app again. You’ll see that the favorite tab is shown despite your previous change. Your first task is to preserve the state of this toggle when the user closes and reopens the app.
Open SettingsView. You’ll see that the isOn
property of the toggle
that shows and hides the favorite tab binds to the isFavTabVisible
property from joyJotterVM
. Add an onChange
modifier to this toggle to save the value of the isFavTabVisible
property. Whenever the value of the isFavTabVisible
changes, this method will write this value to UserDefaults using the direct approach for the key isFavTabVisible
, as you learned in the previous section.
.onChange(of: joyJotterVM.isFavTabVisible) { _, newValue in
UserDefaults.standard.set(newValue, forKey: "isFavTabVisible")
}
Next, you need to read this value from UserDefaults into the isFavTabVisible
property when the user reopens the app. The best place to read this value is when the user displays the tab view since this change will affect the appearance of one of the tabs. Open ContentView. Then, add the onAppear
modifier to the end of TabView
to read the bool value with the key isFavTabVisible
from UserDefaults. Then, set it to the isFavTabVisible
property.
.onAppear {
joyJotterVM.isFavTabVisible =
UserDefaults.standard.bool(forKey: "isFavTabVisible")
}
Build and run the app. Uncheck the first toggle
in the Settings tab, then restart the app. This time, you’ll see that the favorite tab is still hidden.
Note: You have to wait a second before restarting the app for the change to take effect. This is one of the limitations of the UserDefaults that we talked about in the previous section.
Challenge: Extending UserDefaults to Preserve Joke Card Preferences
Now, it’s time for a small challenge to test your knowledge. In the Settings tab, there’s a second toggle
to show and hide the favorite button in Joke cards. Your challenge is to preserve the state of this toggle
when the user closes and reopens the app. Stop the video, and try it on your own first, then continue the video to check the solution.
For this challenge, you’ll use the same direct approach to write and read the value of this toggle
to and from UserDefaults. First, open SettingsView, then add an onChange
modifier to this toggle to save the value of the isFavVisibleInCard
property.
.onAppear {
joyJotterVM.isFavVisibleInCard =
UserDefaults.standard.bool(forKey: "isFavVisibleInCard")
}
Then, inside ContentView, add another line into the onAppear
modifier to read the bool value with the key isFavVisibleInCard
from UserDefaults. Then, set it to the isFavVisibleInCard
property.
joyJotterVM.isFavVisibleInCard =
UserDefaults.standard.bool(forKey: "isFavVisibleInCard")
Build and run the app. Open the Settings tab, and uncheck the second toggle. Restart the app, then check the joke view. You’ll see that the favorite button is hidden. Congratulations, you successfully preserved data using the direct approach of UserDefaults. Now, you’ll implement the second approach.
Enhancing User Experience with @AppStorage and UserDefaults
One convenient functionality in user-friendly apps is the ability to reopen the app on the last tab the user accessed. You’ll now integrate this feature into the JoyJotter app using the second approach with UserDefaults.
Open ContentView. Then, add a new property with the @AppStorage
property wrapper. Give it an initial value of 0.
@AppStorage("selectedTab") private var savedSelectedTab: Int = 0
Then bind this property to the selection of the TabView
. This will make the changes in the TabView
selection saved to the UserDefaults and easily retrieved and used using the @AppStorage
property.
TabView(selection: $savedSelectedTab)
Finally, add a new line in the onAppear
modifier to read the value from UserDefaults property and assign it to the selectedTab
property.
selectedTab = savedSelectedTab
Build and run the app. Select the Settings tab then wait for a second before restarting the app. Notice how the app reopens on the Settings tab which is the last accessed one.