Storing Custom Data Types in UserDefaults Using Property Wrappers in Swift

Phil Zakharchenko / Zet
Oct 30 · 2 min read
Image for post
Image for post
Property Wrappers in Swift are awesome.

Property Wrappers in Swift are awesome.

One of the “classic” use cases for them is storing data. And it can be dead simple, especially when it comes to using UserDefaults. It can simplify your code down to something like @UserDefault var x = 0. I am not going to talk about how to write a simple UserDefaults wrapper here, because it has been done hundreds of times (check out this article by Paul Hudson if that’s what you’re looking for).

But let’s face it, UserDefaults can be a pain when working with more complex data types. You might need to provide custom encoding/decoding mechanisms, and your little property wrapper will be no help in that case.

Here I try to provide two ways that I deal with the issue in my projects.

Option 1. Codable

The easiest scenario is when your data type actually conforms to Codable. In this case, we can abstract away the encoding/decoding process and end up with the same straightforward declaration.

Codable UserDefaults

Which means that we won’t ever have to supply any other information in our initialization:

@CodableUserDefault(“dict”, defaultValue: [0: 0])private var dict: [Int: Int]

Pretty easy, right? But what if… our data doesn’t conform to Codable, and we either can’t or don’t want to modify our data types?

Option 2. Custom Encoding

We can solve this with closures. In this case, our property wrapper will use the closures we provide to convert between the stored type and the actual type on demand. Again, this is a great way to abstract our encoding/decoding logic, but we do need to provide some information.

This way of doing things actually allows us to store any data type in UserDefaults — a problem that would otherwise cause a lot of headache — and boilerplate.

Here’s what I came up with.

Custom-encoded UserDefaults

And indeed we will have to supply a bit of extra information when we initialize a property as well. Something like this:

In this case, our custom struct of type Prefs gets converted to Int to be stored, and we control the whole process, meaning that we can customize and change anything at any time without writing any more code than needed.

I just started this blog, so if you like this, consider giving me a follow. I’m an iOS dev and will post stuff related to it, as well as other (fun) technical things.

The Startup

Medium's largest active publication, followed by +734K people. Follow to join our community.

Phil Zakharchenko / Zet

Written by

iOS Engineer, Entrepreneur, CS Student at Georgia Tech

The Startup

Medium's largest active publication, followed by +734K people. Follow to join our community.

Phil Zakharchenko / Zet

Written by

iOS Engineer, Entrepreneur, CS Student at Georgia Tech

The Startup

Medium's largest active publication, followed by +734K people. Follow to join our community.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store