20. Apr 2023
iOSExploring our iOS toolbox - How to save values to UserDefaults & KeyChain in Swift
Swift UserDefaults is a simple and lightweight way to store small amounts of data in your application, such as user preferences, settings, and application state. However, working with UserDefaults and Keychain can be cumbersome, this is where the GoodPersistence swift package comes in.
Storing data in UserDefaults
We use the UserDefaultValue
class, which is a property wrapper that enables the storage of any Codable
conforming value in UserDefaults.
To use this class, you can simply create an instance of the UserDefaultValue
class and pass in the key and default value for the property wrapper.
For example, if you want to store a user's name in UserDefaults, you can create an UserDefaultValue
instance like this:
@UserDefaultValue("userName", defaultValue: "Guest")
var userName: String
In the example above, the key "userName" will be used to store the user's name in UserDefaults. If no value for this key exists, the default value "Guest" will be used instead.
This property wrapper also provides another useful function, observing changes using Combine.
🔐 Storing data in KeyChain
If you’ve ever struggled with storing sensitive data inside the Keychain, with GoodPersistence package it’s never been easier.
To save values inside the KeyChain we use another wrapper, called KeychainValue
. Let me show you how does it work:
struct UserSensitiveInformation {
let userId: String
let dateOfBirth: Date
let address: String
}
@KeychainValue(
String(describing: UserSensitiveInformation.self),
defaultValue: nil
accessibility: .afterFirstUnlockThisDeviceOnly
)
var userSensitiveInformation: UserSensitiveInformation?
For example above we have a struct called UserSensitiveInformation
which holds all of the sensitive data that we want to securely store inside the Keychain
.
As you can see, the implementation is quite similar to the previous example that uses UserDefaults
.
We declare a key and its default value, but in addition to that, there is a accessibility
parameter that we can also specify. This parameter has a default value nil,
which means that you can leave it empty if needed.
The accessibility
parameter determines when the stored data is accessible. In the given code, the value is set to .afterFirstUnlockThisDeviceOnly
, indicating that the data can only be accessed from the keychain once the device is unlocked.
Listen to value changes
In addition to the primary purpose of storing values, UserDefaultValue
and KeychainValue
wrappers also offer a convenient feature for observing value changes using Combine framework.
Let’s say we want to receive updates whenever the userName value changes.
After declaring the userName
variable using the UserDefaultValue
the wrapper as shown in the first example, you can easily declare a publisher for it using the Combine framework.
Here's an example of how to do that:
lazy var userNamePublisher = _userName
.dropFirst()
.eraseToAnyPublisher()
This publisher emits a new value whenever the userName
the variable is changed. To subscribe to updates from the publisher, we can use the sink
or assign
method, which receives a new value whenever the userName
variable changes.
In this example, we simply set the text of a label inside the assing
method:
var cancellable: AnyCancellable?
let userNameLabel = UILabel()
cancellable = userNamePublisher
.removeDuplicates()
.assing(to: \\.text, on: userNameLabel, ownership: .weak)
These examples also works for KeychainValue
wrapper. No additional setup is needed.
Congrats!
You have gone through the process of storing data using the GoodPersistence package.
Now you may be wondering how it works under the hood of the app. Luckily, the package comes with a sample that you can explore to gain a deeper understanding of its functionality.
If you found this package useful, be sure to check out our other packages. Who knows, you might just find another gem that can help take your app to the next level!