SwiftyUserDefaults 4.0

May 1, 2019 18:01 · 4 minute read #open-source #swift #swiftyuserdefaults #iOS

I’m really happy to say that SwiftyUserDefaults 4 was finally released at the end of last week. Due to changes of Swift 4 and 5, the core of the library was rewritten from the ground up. Don’t worry, though, as the API is almost untouched and the new version introduces mostly improvements and additions. Here is a short summary of what’s inside.

Default values

Probably the most noticeable change in version 4 is handling of default values. In version 3 you would do a following:

let key = DefaultsKey<String>("username")
let username = Defaults[key]

And the username would be either the value saved to UserDefaults or a default value ("" for String). Version 4 removes that - now you have to make the default value explicit:

let key = DefaultsKey<String>("username", defaultValue: "admin1")
let username = Defaults[key]

Of course, you might want to use an optional type instead and we support that as well:

let key = DefaultsKey<String?>("username")
let username = Defaults[key]

You can also set a default value for an optional key. Be careful, though! The behavior of default value is “either return a value that is stored in UserDefaults or return the default value”. This means that if you save nil, you will receive the default value when accessing the key. In case you want to only set the value at the very first time, you would have to do it manually.

Codable, NSCoding, enums

Version 4 introduces a new protocol, DefaultsSerializable. If you want to store any type that implements Codable, NSCoding or is an enum, just add DefaultsSerializable to the implementation list of your type:

final class Frog: Codable, DefaultsSerializable {
    let name: String
extension UIColor: DefaultsSerializable {}

No implementation needed! If you, however, would have a custom type that you would like to store in UserDefaults, then…

Custom types

… worry no more. Version 4 was written with customization in mind - it uses “bridges” to know the get/set protocol for a type. You can check this part of the Readme to get the details of how to implement your own bridge or how to replace an existing one for a type, but here is an example of a bridge that persists the value as an Int:

open class DefaultsIntBridge: DefaultsBridge<Int> {
    open override func save(key: String, value: Int?, userDefaults: UserDefaults) {
        userDefaults.set(value, forKey: key)

    open override func get(key: String, userDefaults: UserDefaults) -> Int? {
        if let int = userDefaults.number(forKey: key)?.intValue {
            return int

        // Fallback for launch arguments
        if let string = userDefaults.object(forKey: key) as? String,
            let int = Int(string) {
            return int

        return nil

KVO support

We also introduced a layer on top of UserDefaults and KVO so it feels more Swifty 😉

let key = DefaultsKey<String?>("username")
Defaults.observe(key: key) { update in
	// here you can access `oldValue`/`newValue` etc.

Launch arguments support

Updating UserDefaults using launch arguments seems to be a hot topic and we don’t want to take all the fun from you. Version 4 supports String, Bool, Double and Int based launch arguments.

func testExample() {
    let app = XCUIApplication()
    app.launchArguments = ["-skipLogin", "true", "-loginTries", "3", "-lastGameTime", "61.3", "-nickname", "sunshinejr"]

CocoaPods / Carthage / SwiftPackageManager support

It’s important for us to get this release out to everyone that wants to play with it. Because of that, we support all of the package managers mentioned above and have integration tests for each one of them that runs on every pull request.

Swift 4.1 / 4.2 / 5.0 & Xcode 10.2 support

And the CI integration doesn’t stop on package managers only. We also have multiple Swift version builds to compliment the package managers integration tests. This should make the maintenance of this library a lot easier in the future.

Migration guide

Here is a migration guide if you are transitioning from version 3 to 4.


All of this and more available at GitHub. Hope you all enjoy it.