First introduced in Swift 5.1, property wrappers allow us devs to add our own implementation details to a property before they are initialized. Currently, by delaying initialization we can declare a property as lazy, and then return our property when it’s first requested. Property wrappers allow us to wrap all this logic into a nice separate piece of code that can be attached to any property like the way lazy does. This opens a whole new way of creating properties.
Combine introduced one property wrapper called Published which can be assigned to a property to expose a publisher for that value.
Swift UI also exposes multiple new property wrappers in Swift 5.1.
@Binding – allows the properties value to live somewhere else and is shared in both places. For example, in SwiftUI when you initialize a TextField you pass it in a Binding property, which is then updated when the text is inputted by the user.
@Environment – is used to read individual data from the environment with the associated key. A common example would be if you need to read size class information.
@EnvironmentObject – similar to the environment property wrapper. This allows properties to be assigned to the entire object from the environment.
@FetchRequest – will return any NSFetchRequestResult object that has been saved to the environment. For anyone using CoreData, this will allow requests to be done directly on the property. As this property wrapper also conforms to DynamicProperty, values will be automatically refreshed when they are changed.
@GestureState – Gesture states will reset the value to its initial value once the gestures finishes.
@ObservedObject – can be attached to any ObservableObject property, to receive updates when the underlying object changes.
@State – state properties can be used to store basic information within a View. By attaching the @State property wrapper, it allows us to mutate values inside a struct.
That was a look at the built-in property wrappers but it is possible to create your own. Below is a very straight forward example of how you can change property values as they’re about to be initialised.
I have a simple weather struct that has its values set from a JSON feed. The feed only returns its temperatures in degrees, however I want to use Fahrenheit.
I could add a private property for each temperature and override the setter and getter to use the private version.
However, there is a lot of boilerplate and duplication here which is very messy. Wouldn’t it be similar if we could wrap all this logic up and assign it to the property in one word?
Here we have my Fahrenheit property wrapper which will automatically convert the property’s value from Celsius to Fahrenheit. It can then be assigned as follows.
There we have it. A really nice elegant way of wrapping any initialization logic for your properties. Be sure to check out the Swift proposal for property wrappers which has way more information than I could ever write about.