UserDefaults for storing data in iOS iOS 01.09.2019

Your application will need a way to store this information, retrieve it, and possibly search and sort this data. Working with data can sometimes be difficult. Fortunately, Apple has provided methods and frameworks to make this process easier.

There are some things to consider when deciding where to store certain kinds of information. The easiest way to store information is within the preferences file, but this method has some downsides:

  • All of the data is both read and written at the same time. If you are going to be writing often or writing and reading large amounts of data, this could take time and slow down your application. As a general rule, your preferences file should never be larger than 100 KB. If your preferences file starts to become larger than 100 KB, consider using Core Data as a way to store your information.
  • The preferences file does not provide many options when it comes to searching and ordering information.

The preferences file is really nothing more than a standardized XML file with accompanying classes and methods to store application-specific information. A preference would be, for example, the sorting column and direction (ascending/ descending) of a list. Anything that is generally customizable within an app should be stored in a preferences file.

Sensitive data should not be stored in the preferences file or in a database without additional encryption. Luckily, Apple provides a way to store sensitive information. It is called the keychain.

Apple has provided developers with the UserDefaults class; this class makes it easy to read and write preferences for iOS, macOS, tvOS, and watchOS. The great thing is that, in this case, you can use the same code for iOS, macOS, and tvOS. The only difference between the several implementations is the location of the preferences file.

On iOS, the preferences file is located in your application’s container in the /Library/Preferences folder.

All you need to do to write preferences is to create a UserDefaults object. This is done with the following line:

var prefs: UserDefaults = UserDefaults.standard

This instantiates the prefs object so you can use it to set preference values. Next, you need to set the preference keys for the values that you want to save.

Once you have instantiated the object, you can just call set(_:forKey:) to set an object. If you wanted to save the username of sherlock.holmes, you would call the following line of code:

prefs.set("sherlock.holmes", forKey: "username")

After a certain period of time, your app will automatically write changes to the preferences file. You can force your app to save the preferences by calling the synchronize function, but this should only be used if you cannot wait for the next synchronization interval such as if your app is immediately going to exit. To call the synchronize function, you would write the following line:


With just three lines of code, you are able to create a preference object, set a preference value, and write the preferences file. It is an easy and clean process. Here is all of the code:

let prefs: UserDefaults = UserDefaults.standard
prefs.set("sherlock.holmes", forKey: "username")
prefs.set(10, forKey: "booksInList")

Reading preferences is similar to writing preferences. Just like with writing, the first step is to obtain the UserDefaults object. This is done in the same way as it was done in the writing process:

var prefs: UserDefaults = UserDefaults.standard

Now that you have the object, you are able to access the preference values that are set. For writing, you use the set syntax; for reading, you use the string(forKey:) method. You use the string(forKey:) method because the value you put in the preference was a String. In the writing example, you set preferences for the username and for the number of books in the list to display. You can read those preferences by using the following simple lines of code:

let username = prefs.string(forKey: "username")
let booksInList = prefs.integer(forKey: "booksInList")

You can check if there is a value usung following snippet

extension UserDefaults {
    static func contains(_ key: String) -> Bool {
        return UserDefaults.standard.object(forKey: key) != nil

Save custom objects into UserDefaults using Codable

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.

Structs can’t be directly stored in UserDefaults because UserDefaults does not know how to serialize it. As UserDefaults is backed by plist files, struct needs to be converted representation supported by it.

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

extension UserDefaults {
    func setObject<T: Codable>(_ value: T?, forKey defaultName: String){
        let data = try? JSONEncoder().encode(value)
        set(data, forKey: defaultName)

    open func getObject<T>(_ type: T.Type, forKey defaultName: String) -> T? where T : Decodable {
        guard let encodedData = data(forKey: defaultName) else {
            return nil

        return try! JSONDecoder().decode(type, from: encodedData)


struct Movie: Codable {
    var title: String
    var year: Int 


let movieKey = "MOVIE_KEY"
UserDefaults.standard.setObject(Movie(title: "Movie", year: 2020), forKey: movieKey)
if let movie = UserDefaults.standard.getObject(Movie.self, forKey: movieKey) {
    print("Movie: \(movie)")