Как сказал @vadian, все эти проверки типов можно заменить одним вызовом UserDefaults.standard.object()
и условным приведением типов. Также тип свойства value
должен быть необязательным для обработки случая, когда свойство не установлено (или имеет неправильный тип):
struct DefaultKey<T> {
let storageKey: String
var value: T? {
get {
return UserDefaults.standard.object(forKey: storageKey) as? T
}
nonmutating set {
UserDefaults.standard.set(newValue, forKey: storageKey)
}
}
}
И затем вы можете определить ограниченное расширение метод, в котором вы специализируете вычисляемое свойство для случая типов RawRepresentable
:
extension DefaultKey where T: RawRepresentable {
var value: T? {
get {
if let rawValue = UserDefaults.standard.object(forKey: storageKey) as? T.RawValue {
return T(rawValue: rawValue)
}
return nil
}
nonmutating set {
UserDefaults.standard.set(newValue?.rawValue, forKey: storageKey)
}
}
}
Пример использования:
enum Direction : Int {
case left = 0
case right = 1
}
let key1 = DefaultKey<Int>(storageKey: "foo")
key1.value = 123
let key2 = DefaultKey<Direction>(storageKey: "bar")
key2.value = .right
print(key1.value as Any) // Optional(123)
print(key2.value as Any) // Optional(Direction.right)
Обратите внимание, что это все еще может взломать sh, если используется с не -типы списка свойств. На всякий случай вам придется ограничить расширения типами, которые, как известно, являются сохраняемыми по умолчанию пользователем (целые числа, числа с плавающей запятой, строки, ...):
protocol UserDefaultsStorable {}
extension Int: UserDefaultsStorable {}
extension Float: UserDefaultsStorable {}
// ...
struct DefaultKey<T> {
let storageKey: String
}
extension DefaultKey where T: UserDefaultsStorable { .. }
extension DefaultKey where T: RawRepresentable, T.RawValue: UserDefaultsStorable { ... }