<div dir="ltr"><div>Here&#39;s yet another alternative. I read an article doing this very thing a while back, it might be interesting to you: <a href="http://radex.io/swift/nsuserdefaults/static/">http://radex.io/swift/nsuserdefaults/static/</a>. It makes the key type a class instead, and inherits from a non-generic parent class to which it adds the static properties.</div><div><br></div><div>The gist of it is roughly like this (although the article uses subscript, which does not allow for a generic implementation so I use a get/set approach here for brevity):</div><div><div><br></div><div>```</div><div><div><font face="monospace">class DefaultsKeys {}</font></div><div><font face="monospace">final class DefaultsKey&lt;T&gt;: DefaultsKeys {</font></div><div><font face="monospace">    let value: String</font></div><div><font face="monospace"><br></font></div><div><font face="monospace">    init(_ value: String) {</font></div><div><font face="monospace">        self.value = value</font></div><div><font face="monospace">    }</font></div><div><font face="monospace">}</font></div><div><font face="monospace"><br></font></div><div><font face="monospace">extension UserDefaults {</font></div><div><font face="monospace">    func get&lt;T&gt;(_ key: DefaultsKey&lt;T&gt;) -&gt; T? {</font></div><div><font face="monospace">        return object(forKey: key.value) as? T</font></div><div><font face="monospace">    }</font></div><div><font face="monospace"><br></font></div><div><font face="monospace">    func set&lt;T&gt;(_ key: DefaultsKey&lt;T&gt;, to value: T) {</font></div><div><font face="monospace">        set(value, forKey: key.value)</font></div><div><font face="monospace">    }</font></div><div><font face="monospace">}</font></div><div><font face="monospace"><br></font></div><div><font face="monospace">extension DefaultsKeys {</font></div><div><font face="monospace">    static let version = DefaultsKey&lt;String&gt;(&quot;version&quot;)</font></div><div><font face="monospace">}</font></div><div><font face="monospace"><br></font></div><div><font face="monospace">let defaults = UserDefaults.standard</font></div><div><font face="monospace">defaults.set(.version, to: &quot;1.0&quot;)</font></div><div><font face="monospace">let version = defaults.get(.version)</font></div><div><font face="monospace">print(version ?? &quot;N/A&quot;)</font></div></div><div>```</div></div></div><br><div class="gmail_quote"><div dir="ltr">On Fri, 7 Jul 2017 at 14:00 Vladimir.S via swift-users &lt;<a href="mailto:swift-users@swift.org">swift-users@swift.org</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On 07.07.2017 14:02, Thierry Passeron via swift-users wrote:<br>
&gt; Hi Everyone,<br>
&gt;<br>
&gt; Using Swift 3.1, I was wondering if I could come up with something largely inspired by Notification.Name to help me deal with UserDefaults so I started by doing something like:<br>
<br>
The only kind of solution I was able to implement, is with calculated properties in<br>
extension. Hope this have any sense and most likely can be improved(code from swift<br>
sandbox):<br>
<br>
struct DefaultsKey&lt;T&gt; {<br>
        var rawValue : String<br>
<br>
        init(_ name: String) {<br>
                rawValue = name<br>
        }<br>
}<br>
<br>
extension DefaultsKey {<br>
        static var version : DefaultsKey&lt;String&gt; { return DefaultsKey&lt;String&gt;(&quot;version&quot;) }<br>
        static var code : DefaultsKey&lt;Int&gt; { return DefaultsKey&lt;Int&gt;(&quot;code&quot;) }<br>
}<br>
<br>
func UserDefaults_standard_object(forKey: String) -&gt; Any? {<br>
        switch forKey {<br>
                case &quot;version&quot; : return &quot;1.0.0&quot;<br>
                case &quot;code&quot; : return 12345<br>
                default : return nil<br>
        }<br>
}<br>
<br>
func Defaults&lt;T&gt;(_ key: DefaultsKey&lt;T&gt;) -&gt; T? {<br>
   return UserDefaults_standard_object(forKey: key.rawValue) as? T<br>
}<br>
<br>
let version = Defaults(.version)<br>
let code = Defaults(.code)<br>
<br>
print(version ?? &quot;-no value-&quot;, type(of: version)) // 1.0.0 Optional&lt;String&gt;<br>
print(code ?? &quot;-no value-&quot;, type(of: code))       // 12345 Optional&lt;Int&gt;<br>
<br>
<br>
<br>
&gt;<br>
&gt; public struct DefaultsKey: RawRepresentable, Equatable, Hashable, Comparable {<br>
&gt;<br>
&gt;    public var rawValue: String<br>
&gt;    public var hashValue: Int { return rawValue.hash }<br>
&gt;<br>
&gt;    public init(_ rawValue: String) { self.rawValue = rawValue }<br>
&gt;    public init(rawValue: String) { self.rawValue = rawValue }<br>
&gt;<br>
&gt;    /* Protocols implementation .. */<br>
&gt; }<br>
&gt;<br>
&gt; Now I can make extensions like:<br>
&gt;<br>
&gt; extension DefaultsKey {<br>
&gt;    static let version = DefaultsKey(&quot;version »)<br>
&gt; }<br>
&gt;<br>
&gt; And use it to query the UserDefaults.<br>
&gt;<br>
&gt; public func Defaults&lt;T&gt;(_ key: DefaultsKey) -&gt; T? {<br>
&gt;    return UserDefaults.standard.object(forKey: key.rawValue) as? T<br>
&gt; }<br>
&gt;<br>
&gt; let version: String? = Defaults(.version)<br>
&gt;<br>
&gt; Nice, concise, I love it…<br>
&gt;<br>
&gt; But It could be even better to let the compiler check the return type of the UserDefault for the DefaultKey that I ask if only I could create the key and bind it to a type. So I tried this:<br>
&gt;<br>
&gt; public struct DefaultsKey&lt;T&gt;: RawRepresentable, Equatable, Hashable, Comparable {<br>
&gt; …<br>
&gt; }<br>
&gt;<br>
&gt; extension DefaultsKey {<br>
&gt;    static let version = DefaultsKey&lt;String&gt;(&quot;version »)<br>
&gt; }<br>
&gt;<br>
&gt; But this doesn’t compile:<br>
&gt;     error: static stored properties not supported in generic types<br>
&gt;<br>
&gt; I guess I could keep all the keys outside an extension scope but then it would not be as concise as with Notification.Name<br>
&gt;<br>
&gt; Please let me know if there is indeed a generic way to solve this. Any help would be greatly appreciated.<br>
&gt; Thanks in advance.<br>
&gt;<br>
&gt; Thierry.<br>
&gt; _______________________________________________<br>
&gt; swift-users mailing list<br>
&gt; <a href="mailto:swift-users@swift.org" target="_blank">swift-users@swift.org</a><br>
&gt; <a href="https://lists.swift.org/mailman/listinfo/swift-users" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-users</a><br>
&gt;<br>
_______________________________________________<br>
swift-users mailing list<br>
<a href="mailto:swift-users@swift.org" target="_blank">swift-users@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-users" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-users</a><br>
</blockquote></div>