首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >测试是否符合RawRepresentable协议并转换为to协议

测试是否符合RawRepresentable协议并转换为to协议
EN

Stack Overflow用户
提问于 2020-06-20 17:18:46
回答 1查看 47关注 0票数 1

我有一些通用代码,允许我在默认系统中读取和写入各种类型,例如,值getter和setter:

代码语言:javascript
复制
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>,例如

代码语言:javascript
复制
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

我已经尝试了每一个whereas咒语,直到我开始怀疑它是否能做到!?

我在Swift 5中,目标是通过调用CustomType(rawValue:)来创建新实例,并通过调用myValue.rawValue来获取Int值。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-06-20 19:04:49

正如@vadian所说,所有这些类型检查都可以被替换为对UserDefaults.standard.object()和条件强制转换的单个调用。此外,value属性的类型需要是可选的,以处理属性未设置(或类型不正确)的情况:

代码语言:javascript
复制
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类型专门化computed属性:

代码语言:javascript
复制
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)
        }
    }
}

示例用法:

代码语言:javascript
复制
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)

请注意,如果与非属性列表类型一起使用,这仍然可能会崩溃。为了安全起见,您必须将扩展限制为已知为用户默认可存储的类型(整数、浮点数、字符串等):

代码语言:javascript
复制
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 { ... }
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62483918

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档