Save custom objects into UserDefaults using Codable in Swift 5.1 (Protocol Oriented Approach)

iOS supports several types of objects that we can directly save into UserDefaults like Int, String, Float, Double, Bool, URL, Data or collection of these types.

But what if we want to save custom objects into UserDefaults?🤔

According to Apple:

If you want to store any other type of object, you should typically archive it to create an instance of NSData.

Apple Documentation

Now as we know that if we want to save our custom object into UserDefaults we need to first convert it into the Data object. Fortunately, we have several options to do so. We will use the latest and my favourite Codable for this.

No developer wants to have boilerplate code in their projects, so we will be doing it using a protocol😎. We will be creating an array of methods that we will write once and can use them anywhere in the project.

Let’s define a protocol ObjectSavable that declares method requirements using which we will be able to save and retrieve custom objects to and from UserDefaults:-

Protocol ObjectSavable and its requirements

setObject method accepts an object whose type conforms to Encodable protocol and a key that we want to associate with it.

getObject method accepts a key by which we will retrieve the associated object from UserDefaults and a type that conforms to the Decodable protocol. Note that to pass a type itself we have used Metatype😕.

A metatype type refers to the type of any type, including class types, structure types, enumeration types, and protocol types.

Apple Documentation

Our ObjectSavable protocol is ready, let’s conform UserDefaults class to it and provide the implementation to its requirements.

UserDefaults Conforming to ObjectSavable protocol

Let’s talk about what’s going on here in the method implementations:-


We have created a JSONEncoder object using which the custom object will be converted into the Data object. Once we have the converted Data object, we will save it into the UserDefaults with the given key.


We will retrieve the object from UserDefaults for the given key. Using a guard statement we will safely bind the retrieved Data object to a property. Finally, we will decode this Data object into the given type and return it.

Note:- If any of the above methods fails on any step, it throws a relevant error that suggests the developer what possibly gone wrong.

To manage the failures I have created an enum ObjectSavableError of raw type String which is conforming to LocalizedError protocol.

ObjectSavableError declaration

All the hard work is done💪🏻. Now let’s do an example.

Declare a struct Book as follows:-

Book declaration

Now let see how we can use the above methods to save and retrieve objects:-


Create an object of Book, pass it and a key to the setObject method. As this method can throw an error on failure, we are using the do-catch statement.

Save object


Getting back a saved object is as easy as saving it. Just pass a key and a type to the getObject method.

Retrieve object

This his how you can save and retrieve custom types into UserDefaults.🎉.

This is my first blog ever and it’s been an amazing experience writing it😇. I hope this will help you. If you have any questions you can ask in the comment section. Thank you😃



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
Ankit Bhana

Ankit Bhana


iOS Developer at Y Media Labs | Swift Enthusiast | Coffee Lover ☕️