Reading and writing User Defaults in Swift

Insert image description here

Preface

User Defaults is the preferred solution for Swift apps to store preferences that persist between app launches. It is a key-value store backed by property list (plist) files. Since this type of storage is supported, you need to know what storage types are supported.

There are some best practices when using User Defaults. I can also recommend specific solutions based on implementation experience using it in dozens of applications. Let’s dig into it!

Introducing User Defaults

Applications often use User Defaults to store the user's preferences. You can store preferences, such as a user's favorite stocks or save specific user statuses, such as "User has seen the lead."

Code to store these preferences could look like this:

UserDefaults.standard.set(true, forKey: "has-seen-onboarding")
UserDefaults.standard.set(["AAPL", "TSLA"], forKey: "favorite-stocks")

print(UserDefaults.standard.bool(forKey: "has-seen-onboarding")) 
// 打印:true
print(UserDefaults.standard.array(forKey: "favorite-stocks")) 
// 打印:["AAPL", "TSLA"]

In this case, we used the standard User Defaults container. In most cases this will be enough. However, you may want to consider using the group User Defaults .

Share User Defaults

Share User Defaults with other apps and extensions

Using so-called app groups, you can share User Defaults containers with other apps and extensions. I highly recommend using this technique from the beginning, even though there may not be a need to share preferences now, you will thank yourself later if you add extensions that need to read or write preferences from the main application.

To configure application groups, you need to add a new feature to the project settings:

You can start sharing User Defaults with other apps and extensions by adding the App Groups feature.

You can find detailed instructions in Apple's documentation. Once configured, you can create new instances using the group identifier:

extension UserDefaults {
    
    
    static let group = UserDefaults(suiteName: "group.your.identifier")
}

Now, you can access the shared group container by using static properties:

UserDefaults.group.set(["AAPL", "TSLA"], forKey: "favorite-stocks")

Any application or extension using the same application group can now read and write favorite stocks. I use this technique in Stock Analyzer to populate widgets based on favorite stocks configured in the main application.

User Defaults storage data type

The property list must support the objects you store in User Defaults. Whenever you try to write to an unsupported object, you will immediately encounter the following error:

*** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘Attempt to insert non-property list object UserDefaults.Stock(symbol: “AAPL”) for key last-opened-stock’

In this case I'm trying to store a codable object:

struct Stock: Decodable {
    
    
    let symbol: String
}

UserDefaults.group.set(Stock(symbol: "AAPL"), forKey: "last-opened-stock")

Whenever you encounter such an exception, you must transform the data before storing it. You can use JSONEncoder to encode an instance to data and decode the value when reading it.

User Defaults supports the following types:

  • data
  • string
  • Number (NSNumber)
  • date
  • array
  • dictionary
  • Boolean value

If your type is not on this list, you need to find a way to convert it to any supported type.

Respond to changes

Although you can use didChangeNotification to observe changes, I recommend looking at a managed solution like the User Defaults Property Wrapper for monitoring changes in real time.

Monitor User Defaults changes

When dealing with functionality that interacts with User Defaults, you want to have a way to monitor changes in real time. To solve this problem, I built a User Defaults editor in RocketSim that allows you to edit and monitor key-value pairs in real time.

For example, in the video below I am developing the tooltip shown in the WeTransfer app. The tooltip should only be shown once per user and I want to make sure the User Defaults key hasShownUploadFilesTooltip is updated accordingly. You can open the editor by clicking the execute button and selecting the User Defaults plist file.

RocketSim's User Defaults editor allows you to edit and view User Defaults values ​​in real time.

The editor constantly monitors the value and flashes a blue background color when the value changes. In the meantime, I can reset the value using a switch and restart the application using RocketSim to see if the tooltip shows up again.

You can imagine this greatly speeds up the workflow of testing implementations that rely on User Defaults. The best part is you can get started and use the standard suite of test editors for free, just install RocketSim from the Mac App Store.

Override User Defaults settings

Override the User Defaults setting for debugging purposes

Although using RocketSim facilitates optimal changes and debugging, you may want to use scenario settings to override the User Defaults settings during debugging.

Alternatives Considered

User Defaults is a good solution in most cases, but if you store sensitive data or want to access data across devices, you may want to explore other solutions.

Keychain for security

User Defaults are not sufficient to store sensitive data. User credentials, API keys, or other sensitive data should be stored in keychain.

CloudKit for cross-platform

Consider using NSUbiquitousKeyValueStore if you want your preferences to be accessible from other Apple devices where your app is installed. It's a similar key-value store, but uses iCloud as the backing store.

in conclusion

You can use User Defaults to store preferences and capture state between app launches. App groups are great for sharing preferences with other apps and extensions, you'll want to pay close attention to the type of data you can store. By monitoring supporting storage, you will ensure that no data is accidentally stored. When data needs to be accessed across devices or sensitive data needs to be stored, it's best to look at alternative solutions.

Guess you like

Origin blog.csdn.net/qq_36478920/article/details/134863975