Data Persistence in SwiftUI

Jun 20 2024 · Swift 5.9, iOS 17.2, Xcode 15.1

Lesson 01: Storing Data with UserDefaults

Demo

Episode complete

Play next episode

Next
Transcript

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.

See forum comments
Cinema mode Download course materials from Github
Previous: Instruction Next: Conclusion