Storing Properly Wrapped Properties

Another UserDefaults property wrapper in Swift

Giovani Pereira
Better Programming

--

Base Photo by Arturo Esparza on Unsplash

If you work with Swift and iOS development, you most likely came across the UserDefaults, an easy way to persistently store user properties on key-value storage.

More on the Apple documentation about the UserDefaults: https://developer.apple.com/documentation/foundation/userdefaults

Great! But… in order to use it, you'll need a reference to the correct Defaults instance, to the storage key, in order to access the value… and if the key has not a stored value yet, the result would be nil, and not some predefined default value.

So, is there a way to use the UserDefaults on a generic property, that stores the last value, and the next time I try to access it, it will bring me the stored value with support for custom default values???

That, my fellow developer, is where we use the property wrappers.

Property Wrappers?

Yes. Property Wrappers.

They are a nice Swift capability, that allows us to add modifiers to properties. Basically, what we want to do is create a wrapper, that will encapsulate all the UserDefaults logic, and give us the stored value.

Preparing the terrain

Since the UserDefaults is a key-value storage unit, we will need something to be our storage keys, so let's make a protocol to help us later:

Here, we have a nice protocol and an extension to make it easier to use enums with String raw types as Storage Keys.

And to make it even easier to access the UserDefault with our storage keys, let's make some helper methods using the Defaults and our StorageKey protocol.

Building the Wrapper

We want to support a few things on our wrapper:

  • property Get: fetches stored value;
  • property Set: updates stored value;
  • support a default value when there is no stored value for the key;
  • support storing different types;

So, let's start writing our wrapper, it will need 2 dependencies, a Value that represents the stored value type, and our StorageKey. With them, we can implement the wrappedValue property to access the UserDefaults.

Here, every time we access our wrapped property, we are actually getting the value on the UserDefaults, and, in case it doesn't exist, we are returning the default value.

And when we set the property value, it will store it on the user defaults as well.

Using it

Nice! We have made a new property wrapper… but how do we use it?

We just need to wrap it around any property we'd like, and now, every time we access it, we'll be indirectly accessing the stored value on user defaults.

You can create a Storage class to center all of your Stored properties:

You can also add it directly where you need it:

What next?

Property Wrappers are a very nice way to encapsulate behaviors and simplify a lot of places where you need to repeat some stuff.

This is part of a code I have actually used, but my idea is more to demonstrate how you can use the wrappers for clever solutions in your own projects.

And, that’s all for the day!

Thanks for reading, and keep wrapping up your properties!

--

--