DEV Community

Cover image for Data Persistence in Swift: UserDefaults
mrcflorian
mrcflorian

Posted on • Edited on

Data Persistence in Swift: UserDefaults

There are multiple ways to persist data in iOS apps. In this article, we are going to talk about UserDefaults. In Swift, UserDefaults API can be used to store small amounts of information about the application or user's settings.

swift userdefaults

For instance, the user should be able to specify the default playback speed or currency that you should display when presenting some stock data. These preferences should be application specific and should be persistent between app launches. However, this data storage is wiped out when users delete the app, so the data is not persistent across app installs.

UserDefaults Example

class UserRepository {
    enum Key: String, CaseIterable {
        case name, avatarData
        func make(for userID: String) -> String {
            return self.rawValue + "_" + userID
        }
    }
    let userDefaults: UserDefaults
    // MARK: - Lifecycle
    init(userDefaults: UserDefaults = .standard) {
        self.userDefaults = userDefaults
    }
    // MARK: - API
    func storeInfo(forUserID userID: String, name: String, avatarData: Data) {
        saveValue(forKey: .name, value: name, userID: userID)
        saveValue(forKey: .avatarData, value: avatarData, userID: userID)
    }

    func getUserInfo(forUserID userID: String) -> (name: String?, avatarData: Data?) {
        let name: String? = readValue(forKey: .name, userID: userID)
        let avatarData: Data? = readValue(forKey: .avatarData, userID: userID)
        return (name, avatarData)
    }

    func removeUserInfo(forUserID userID: String) {
        Key
            .allCases
            .map { $0.make(for: userID) }
            .forEach { key in
                userDefaults.removeObject(forKey: key)
        }
    }
    // MARK: - Private
    private func saveValue(forKey key: Key, value: Any, userID: String) {
        userDefaults.set(value, forKey: key.make(for: userID))
    }
    private func readValue<T>(forKey key: Key, userID: String) -> T? {
        return userDefaults.value(forKey: key.make(for: userID)) as? T
    }
}
Enter fullscreen mode Exit fullscreen mode

Benefits

  • UserDefaults is easy to use, with a simple clean API
  • UserDefaults is thread-safe (you can read and write values from any thread)
  • UserDefaults is shared between the app and the app extensions

Disadvantages

  • Collisions can happen easily
  • Lack of data encryption
  • Not persistent across app installs

Stay tuned for the other articles where I will present a few alternatives to UserDefaults, trying to mitigate some of the limitations outlined above.

Resources

Top comments (0)