sindresorhus / Defaults

💾 Swifty and modern UserDefaults
https://swiftpackageindex.com/sindresorhus/Defaults/documentation/defaults
MIT License
2k stars 120 forks source link

Nested keys strategy recommandation #96

Closed Vincz closed 2 years ago

Vincz commented 2 years ago

Hi guys :) I'm using the Defaults package to store various configuration objects. It looks as follow:

struct Auth: Codable, Defaults.Serializable {
    var sessionToken: String? = nil
    var isAuthenticated: Bool = false
    var user: String? = nil
    var email: String? = nil
}

struct Display: Codable, Defaults.Serializable {
    var displaySeparator: Bool = true
    var spacing = 10.0
    var color1: Color = Color(red: 115/255, green: 250/255, blue: 121/255)
    var color2: Color = Color(red: 255/255, green: 126/255, blue: 121/255)
    var fixedSize: Bool = false
    var maxWidth = 250
}

extension Defaults.Keys {
    static let display = Key<Display>("display", default: Display())
    static let auth = Key<Auth>("auth", default: Auth())
}

It's working well when I'm using the base keys (ie. display and auth). I'm using @Default in my views and Defaults.observe sometimes. Now I would like to be able to use @Default or Defaults.observe on a nested key.
Something like @Default(.display["spacing"]) in my view or Defaults.observe(.display["spacing"]) to observe only a subset.

Is it possible or should I move all the nested keys at the root level like for easy access:

extension Defaults.Keys {
    static let display_displaySeparator = Key<Bool>("display_displaySeparator", default: true)
    static let display_spacing = Key<Int>("display_spacing", default: 10)
    static let display_color1 = Key<Color>("display_color1", default: Color(red: 115/255, green: 250/255, blue: 121/255))
   ...
}

Or should I use the custom types to do that? https://github.com/sindresorhus/Defaults#custom-types But I'm not sure to understand correctly as the example so a really simple struct.

Thanks guy!

sindresorhus commented 2 years ago

I personally only use Codable structs when I need to have multiple instances, for example, in an array. Codable structs have the downside of being harder to change as you cannot later on add a non-optional property to it without some kind of migration. So in general, I prefer namespacing on the key name, like you have done above.

There's no support for observing nested properties and I don't think there will be. There's little benefit to it unless properties on the struct change extremely often.

Vincz commented 2 years ago

@sindresorhus Thank for you reply, it makes perfect sense. I will use the namespacing strategy when I can.