Reputation: 139
This currently works, but in xcode-beta it is now showing a warning:
Same-type requirement makes generic parameter 'Value' non-generic; this is an error in Swift 6
func getUDValue<Value, R>(_ key: String, _ defaultValue: Value) -> Value
where Value == R?, R: RawRepresentable
{
guard let rawValue = UserDefaults.standard.object(forKey: key) as? R.RawValue else {
return defaultValue
}
return R(rawValue: rawValue) ?? defaultValue
}
I understand what it is saying, but trying to remove the Value == R?, R: RawRepresentable
has proven difficult as the R
is needed to access the RawValue
and init(rawValue:)
behind the Optional<RawRepresentable>
Interestingly enough, I got this structure from Apple's own AppStorage initializer for optional RawRepresentables: https://developer.apple.com/documentation/swiftui/appstorage/init(_:store:)-6aj8x
If this is soon to be an error, does anyone know how to accomplish this in the new world?
My current solution was to move these methods into a struct that provides the generic label. See here:
private struct UserDefaultsWrapper<Value> {
static nonisolated func getValue(_ key: String, _ defaultValue: Value) -> Value
where Value: RawRepresentable
{
guard let rawValue = UserDefaults.standard.object(forKey: key) as? Value.RawValue else {
return defaultValue
}
return Value(rawValue: rawValue) ?? defaultValue
}
static nonisolated func getValue<R>(_ key: String, _ defaultValue: Value) -> Value
where Value == R?, R: RawRepresentable
{
guard let rawValue = UserDefaults.standard.object(forKey: key) as? R.RawValue else {
return defaultValue
}
return R(rawValue: rawValue) ?? defaultValue
}
static nonisolated func getValue(_ key: String, _ defaultValue: Value) -> Value
where Value: UserDefaultsPropertyListValue
{
return UserDefaults.standard.object(forKey: key) as? Value ?? defaultValue
}
static nonisolated func getValue<R>(_ key: String, _ defaultValue: Value) -> Value
where Value == R?, R: UserDefaultsPropertyListValue
{
return UserDefaults.standard.object(forKey: key) as? R ?? defaultValue
}
static nonisolated func setValue(_ key: String, _ newValue: Value)
where Value: RawRepresentable
{
UserDefaults.standard.set(newValue.rawValue, forKey: key)
}
static nonisolated func setValue<R>(_ key: String, _ newValue: Value)
where Value == R?, R: RawRepresentable
{
UserDefaults.standard.set(newValue?.rawValue, forKey: key)
}
static nonisolated func setValue(_ key: String, _ newValue: Value)
where Value: UserDefaultsPropertyListValue
{
UserDefaults.standard.set(newValue, forKey: key)
}
static nonisolated func setValue<R>(_ key: String, _ newValue: Value)
where Value == R?, R: UserDefaultsPropertyListValue
{
UserDefaults.standard.set(newValue, forKey: key)
}
}
UserDefaultsPropertyListValue
is a protocol used to extend supported non-RawRepresentable types, e.g. Int, Bool, String, etc.
Upvotes: 1
Views: 87
Reputation: 29242
I think Value
is redundant in this case.
func getUDValue<R>(_ key: String, _ defaultValue: R) -> R
where R: RawRepresentable
{
guard let rawValue = UserDefaults.standard.object(forKey: key) as? R.RawValue else {
return defaultValue
}
return R(rawValue: rawValue) ?? defaultValue
}
You can just remove it and have the type be declared by the resulting property.
let res:Test23? = getUDValue("test", .test)
or
let res:Test23 = getUDValue("test", .test)
Upvotes: 1