Friday, October 6, 2017

Type-Safe User Defaults in Swift

Mike Ash:

To declare a key, write a struct conforming to the TSUD protocol. Inside, implement a single static property called defaultValue which contains the value to be returned if UserDefaults doesn't contain a value:

struct fontSize: TSUD {
    static let defaultValue = 12.0
}

This is an interesting take that uses a new type for each key and then creates the string key from the type’s name. I have been using a simpler system that looks something like this:

// register
extension MJTUserDefaults.IntDefault {
    static let cacheSize = key("CacheSize", 2000)
}

// query
MJTDefaults[.cacheSize]

I like this because it’s compact to register a bunch of keys in sequence and because putting them all into the same type works well for auto-completion.

Update (2017-10-09): Jean-David Gadina (tweet):

The solution I propose is to automate the wrapping code on runtime, using reflection. This used to be done with the Objective-C runtime. With Swift, it’s even easier through the use of the Mirror class.

Update (2017-10-14): Nicolas Bouilleaud:

#function, as per the documentation, “inside a property getter or setter it is the name of that property”. Unfortunately, that means we can’t write:

struct Prefs_ {
    var foo = TSUD<Date>()
}

because in this context, #function would be Prefs_. Using lazy, I guess, implicitely creates a closure, which is called as a getter the first time the property is accessed, and #function is foo.

Comments RSS · Twitter

Leave a Comment