Type-Safe User Defaults in Swift
To declare a key, write a
struct
conforming to theTSUD
protocol. Inside, implement a singlestatic
property calleddefaultValue
which contains the value to be returned ifUserDefaults
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 bePrefs_
. Usinglazy
, I guess, implicitely creates a closure, which is called as a getter the first time the property is accessed, and#function
isfoo
.