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?
Update:
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.
I think
Valueis redundant in this case.You can just remove it and have the type be declared by the resulting property.
or