Blog

Property Wrappers

What is the Property Wrappers

Property Wrappers feature described in SE-0258 proposal, were first introduced in WWDC 2019 and came with Xcode 11 in Swift 5

The main goal is wrapping properties with logic which can be extracted into the separated struct to reuse it across the codebase. Property Wrappers allows us to remove a lot of boilerplate code which we probably all have written in our projects.

Let’s see an example about using UserDefaults:

We all write some code like this. But after adding more and more keys, this’s going to become a very large file with a lot of repetitive parts which is called boilerplate code. This issue is completely resolved after Property Wrappers were introduced.

Using Property Wrappers

This is an implementation for UserDefault Property Wrapper

  1. @PropertyWrapper keyword is an annotation that describes the below struct is a Property Wrapper.
  2. The wrappedValue property is the place where we provide the actual implementation of the wrapper.

Now, Let’s rewrite our UserDefaultsManager using the UserDefault wrapper

That’s it, because our UserDefault wrapper is completely generic, so we can use it to declare any properties of any types. Let’s see how the UserDefaultManager looks like after added some more properties.

It’s really clean right?

By using Property wrappers, we can remove a lot of boilerplate code, and make our code more clean, more simple.

More than that Property Wrappers can be composable. It means you can compose some Property Wrappers when declare a property, like this:

But it’s quite complicated so I will not cover this topic in here. You can get more detail in SE-0258

Now you and me knew what Property Wrappers are and how can use them. But you may get confused about how they work. Let’s go deeper.

How does Property wrappers work?

This is a way we declare a property with a property wrapper

When the compiler compiles our code and saw the above property. It will translate our code to a new one

our property become a computed property, and data is actually managed by $isFirstTimeLaunching. we call properties like this are “synthesized storage properties”. Although we can not see where the $isFirstTimeLaunching is declared or generated in our project, but we can still access to it just by adding $ before our original property name.

That’s it, there is no magic here. You can easily understand the translated code, right?

Declare property with Property Wrappers

We’ve already seen this:

We must not provide a default value for our isFirstTimeLaunching property, if not we’re going to get a compile error

That because when the compiler translates our code, default value of a property with Property Wrappers is always passed into Property Wrapper’s initializer as the first parameter named “wrappedValue“. The above code will be translated like this:

In order to provide a default value for a property which is declared with Property Wrappers, all of Property Wrappers’s initializer must have first parameter named “wrappedValue“.

Let’s take a look into another example:

This is a Property Wrapper which is used for clamping value in a range, and we can declare a property with this Property Wrapper like this:

If we change the initializer of Clamping property wrapper to

We will also get the compile error

To wrap things up, there are several ways to declare property with Property Wrappers:

References

To get a deeper understanding about Property Wrappers, I highly recommend you check out the references below.

  1. Swift evolution – Property Wrappers
  2. WWDC 2019 – Modern Swift API Design
  3. NSHipster – Swift Property Wrappers