Swift 5.1 introduced an interesting concept called Property Wrappers. As the name suggests, it creates a wrapper around any plain old properties in struct , class or enum and enhance their abilities. Let’s dive right into code. Almost every app out there saves some kind of information in UserDefaults. The common approach to do that would be:
struct AppSettings {
// Update the respective value in UserDefault
static var isDarkModeEnabled = false {
didSet {
UserDefaults.standard.setValue(isDarkModeEnabled, forKey: "is_dark_mode_enabled")
}
}
}
Store some value in user defaults when property gets updatedThis is the easiest approach and it works fine. But what if we have more than 1 property to save? Yes, there are many ways we can simplify this but let’s try the magic of property wrapper this time.
How it works:
Property Wrapper simply wraps the original property. Inside this wrapper, you can specify what you want to do when user tries to set the value or read the value from original property. In our case, we will store the value in UserDefaults when user sets the value on original property. Similarly, when user tries the read the value, we will return the stored value from same UserDefaults. Let’s create our very first Property Wrapper.
@propertyWrapper
struct Store {
// Key for UserDefaults
var key: String
// This is the special variable required in Property Wrapper.
var wrappedValue: Bool {
set { UserDefaults.standard.set(newValue, forKey: key) }
get { UserDefaults.standard.value(forKey: key) as? Bool ?? false }
}
init(key: String) {
self.key = key
}
}
// Now we can simplify our AppSettings struct as
struct AppSettings {
@Store(key: "is_dark_mode_enabled") static var isDarkModeEnabled: Bool
}
// value `true` is automatically stored in user defaults with key `is_dark_mode_enabled`
AppSettings.isDarkModeEnabled = true
Let’s break down the steps:
First we create a struct called Store. @propertyWrapper
keyword declares that this struct is actually a property wrapper.
wrappedValue
is a special variable required in Property Wrapper. When we try to read the value of the property, it actually returns the value provided by this wrappedValue
variable. Similarly when we try to set the value of the original property, it actually sets the value for this wrappedValue
.
Since we need some key
to store the value in UserDefaults, we ask for that during initialization.
Using property wrapper is really easy. Just add @Store prefix to any property. That’s it.
Where’s the magic??
The magic happens in this line. AppSettings.isDarkModeEnabled = true Whenever we set the value, it automatically gets stored in UserDefaults with key “is_dark_mode_enabled”. When we try to read the value, it returns the stored value from same UserDefaults.
But…
Our Property Wrapper can work with only Boolean property at this time. Also the default wrapped value is always false. Let’s change that.
Here we ask user to provide both key as well as default value when using this Property Wrapper. We use this key
to save or retrieve value in UserDefaults. We return the defaultValue, if nothing is found in UserDefaults.
With the power of Generics, now this PropertyWrapper can be used with any type of property. Our 10 minutes is Up 👍.
You can learn more about the Property Wrapper from https://docs.swift.org/swift-book/LanguageGuide/Properties.html