测试是否符合 RawRepresentable 协议并转换为 RawRepresentable 协议
Testing for compliance with and casting to RawRepresentable protocol
我有一些通用代码,可以让我读取各种类型并将其写入默认系统,例如值获取器和设置器:
var value : T {
get {
if T.self == Int.self {
return UserDefaults.standard.integer(forKey: storageKey) as! T
} else if T.self == Double.self {
return UserDefaults.standard.double(forKey: storageKey) as! T
} else if T.self == Float.self {
return UserDefaults.standard.float(forKey: storageKey) as! T
} else if T.self == Bool.self {
return UserDefaults.standard.bool(forKey: storageKey) as! T
} else if T.self == String.self {
return UserDefaults.standard.string(forKey: storageKey) as! T
} else {
return UserDefaults.standard.value(forKey: self.storageKey) as! T
}
}
set(value) {
UserDefaults.standard.set(value, forKey: storageKey)
UserDefaults.standard.synchronize()
}
}
现在我想将我自己的枚举类型添加到此机制中,方法是将它们设为 RawRepresentable<Int>
,例如
enum Direction : Int, RawRepresentable {
case left = 0
case right = 1
}
不幸的是,我既找不到测试T
是否符合RawRepresentable
协议的魔术,也无法将T
转换为RawRepresentable
协议,因为无论我尝试什么,我总是以 Protocol 'RawRepresentable' can only be used as a generic constraint because it has Self or associated type requirements
.
结束
我已经尝试了每一个 where
和 as
咒语,直到我开始怀疑它是否可以完成!?
我在 Swift 5,目标是通过调用 CustomType(rawValue:)
创建新实例并通过调用 myValue.rawValue
.
获取 Int 值
正如@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)
请注意,如果与非 属性 列表类型一起使用,这仍然会崩溃。为了安全起见,您必须将扩展限制为已知用户默认可存储的类型(整数、浮点数、字符串...):
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 { ... }
我有一些通用代码,可以让我读取各种类型并将其写入默认系统,例如值获取器和设置器:
var value : T {
get {
if T.self == Int.self {
return UserDefaults.standard.integer(forKey: storageKey) as! T
} else if T.self == Double.self {
return UserDefaults.standard.double(forKey: storageKey) as! T
} else if T.self == Float.self {
return UserDefaults.standard.float(forKey: storageKey) as! T
} else if T.self == Bool.self {
return UserDefaults.standard.bool(forKey: storageKey) as! T
} else if T.self == String.self {
return UserDefaults.standard.string(forKey: storageKey) as! T
} else {
return UserDefaults.standard.value(forKey: self.storageKey) as! T
}
}
set(value) {
UserDefaults.standard.set(value, forKey: storageKey)
UserDefaults.standard.synchronize()
}
}
现在我想将我自己的枚举类型添加到此机制中,方法是将它们设为 RawRepresentable<Int>
,例如
enum Direction : Int, RawRepresentable {
case left = 0
case right = 1
}
不幸的是,我既找不到测试T
是否符合RawRepresentable
协议的魔术,也无法将T
转换为RawRepresentable
协议,因为无论我尝试什么,我总是以 Protocol 'RawRepresentable' can only be used as a generic constraint because it has Self or associated type requirements
.
我已经尝试了每一个 where
和 as
咒语,直到我开始怀疑它是否可以完成!?
我在 Swift 5,目标是通过调用 CustomType(rawValue:)
创建新实例并通过调用 myValue.rawValue
.
正如@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)
请注意,如果与非 属性 列表类型一起使用,这仍然会崩溃。为了安全起见,您必须将扩展限制为已知用户默认可存储的类型(整数、浮点数、字符串...):
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 { ... }