<div dir="ltr"><div>Here'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<T>: 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<T>(_ key: DefaultsKey<T>) -> 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<T>(_ key: DefaultsKey<T>, 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<String>("version")</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: "1.0")</font></div><div><font face="monospace">let version = defaults.get(.version)</font></div><div><font face="monospace">print(version ?? "N/A")</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 <<a href="mailto:swift-users@swift.org">swift-users@swift.org</a>> 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>
> Hi Everyone,<br>
><br>
> 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<T> {<br>
var rawValue : String<br>
<br>
init(_ name: String) {<br>
rawValue = name<br>
}<br>
}<br>
<br>
extension DefaultsKey {<br>
static var version : DefaultsKey<String> { return DefaultsKey<String>("version") }<br>
static var code : DefaultsKey<Int> { return DefaultsKey<Int>("code") }<br>
}<br>
<br>
func UserDefaults_standard_object(forKey: String) -> Any? {<br>
switch forKey {<br>
case "version" : return "1.0.0"<br>
case "code" : return 12345<br>
default : return nil<br>
}<br>
}<br>
<br>
func Defaults<T>(_ key: DefaultsKey<T>) -> 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 ?? "-no value-", type(of: version)) // 1.0.0 Optional<String><br>
print(code ?? "-no value-", type(of: code)) // 12345 Optional<Int><br>
<br>
<br>
<br>
><br>
> public struct DefaultsKey: RawRepresentable, Equatable, Hashable, Comparable {<br>
><br>
> public var rawValue: String<br>
> public var hashValue: Int { return rawValue.hash }<br>
><br>
> public init(_ rawValue: String) { self.rawValue = rawValue }<br>
> public init(rawValue: String) { self.rawValue = rawValue }<br>
><br>
> /* Protocols implementation .. */<br>
> }<br>
><br>
> Now I can make extensions like:<br>
><br>
> extension DefaultsKey {<br>
> static let version = DefaultsKey("version »)<br>
> }<br>
><br>
> And use it to query the UserDefaults.<br>
><br>
> public func Defaults<T>(_ key: DefaultsKey) -> T? {<br>
> return UserDefaults.standard.object(forKey: key.rawValue) as? T<br>
> }<br>
><br>
> let version: String? = Defaults(.version)<br>
><br>
> Nice, concise, I love it…<br>
><br>
> 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>
><br>
> public struct DefaultsKey<T>: RawRepresentable, Equatable, Hashable, Comparable {<br>
> …<br>
> }<br>
><br>
> extension DefaultsKey {<br>
> static let version = DefaultsKey<String>("version »)<br>
> }<br>
><br>
> But this doesn’t compile:<br>
> error: static stored properties not supported in generic types<br>
><br>
> 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>
><br>
> Please let me know if there is indeed a generic way to solve this. Any help would be greatly appreciated.<br>
> Thanks in advance.<br>
><br>
> Thierry.<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>
><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>