Storing Custom Data Types in UserDefaults Using Property Wrappers in Swift
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.
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.
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.