【问题标题】:How to integrate enums in propertyWrapped UserDefault如何在属性 Wrapper UserDefaults 中集成枚举
【发布时间】:2020-09-21 09:46:29
【问题描述】:

下面的结构将适用于原始数据类型,如IntStringDouble 等,有没有办法让这个对枚举起作用,这样我就不必使用 rawValues 和手动解析?

@propertyWrapper
struct Storage<T> {
  let objectName: String
  let defaultValue: T
  let defaults: UserDefaults

  init(_ objectName: String, defaultValue: T, defaults: UserDefaults = .standard) {
    self.objectName = objectName
    self.defaultValue = defaultValue
    self.defaults = defaults
  }

  var wrappedValue: T {
    get { return self.defaults.object(forKey: self.objectName) as? T ?? self.defaultValue }
    set { self.defaults.set(newValue, forKey: self.objectName) }
  }
}

目前我的解决方法是将对象包装在另一个 getter 和 setter 中,这样的枚举。

enum SomeType: String {
  case foo, bar, baz
}


class Defaults {
   @Storage("object", default: "")
   private var: objectContainer: String

   var object: SomeType? {
      get {
         return SomeType(rawValue: self.objectContainer)
      }
      set {
         self.objectContainer = newValue.rawValue ?? ""
      }
   }
}

我尝试为 RawRepresentable 类型创建不同的属性包装器,但 Swift 无法从中推断出 T 的类型。

@propertyWrapper
struct RawRepresentableStorage<T: RawRepresentable> {
  let objectName: String
  let defaultValue: T
  let defaults: UserDefaults
  
  init(_ objectName: String, defaultValue: T, defaults: UserDefaults = .standard) {
    self.objectName = objectName
    self.defaultValue = defaultValue
    self.defaults = defaults
  }
  
  var wrappedValue: T {
    get {
      guard let object = self.defaults.object(forKey: self.objectName) as? T else {
        return self.defaultValue
      }
      
      // Error on this line:
      // `Cannot convert value of type 'T' to expected argument type 'T.RawValue'`
      return T(rawValue: object) ?? self.defaultValue 
    }
    set {
      self.defaults.set(newValue.rawValue, forKey: self.objectName)
    }
  }
}

为代码库中的每个可存储枚举创建包装器类型也不理想,即使只有少数几个

是我遗漏了什么,还是这是 Swift 的当前限制?

【问题讨论】:

    标签: swift enums property-wrapper


    【解决方案1】:

    在您的 wrappedValue getter 中,您正在转换为错误的类型。您将object 传递给T(rawValue:),因此它的类型必须是T.RawValue,而不是T

    @propertyWrapper
    struct RawRepresentableStorage<T: RawRepresentable> {
        let objectName: String
        let defaultValue: T
        let defaults: UserDefaults
        
        init(_ objectName: String, defaultValue: T, defaults: UserDefaults = .standard) {
            self.objectName = objectName
            self.defaultValue = defaultValue
            self.defaults = defaults
        }
        
        var wrappedValue: T {
            get {
                guard let object = self.defaults.object(forKey: self.objectName) as? T.RawValue else {
                    return self.defaultValue
                }
                
                return T(rawValue: object) ?? self.defaultValue
            }
            set {
                self.defaults.set(newValue.rawValue, forKey: self.objectName)
            }
        }
    }
    

    【讨论】:

    • 是的,但T(rawValue: object) 仍然无法编译,因为编译器不知道T 的泛型类型。如果我运行代码会看到这一点,但感谢您的提醒。
    • @ZonilyJame 我的答案中的代码编译得很好,我已经在操场上对其进行了测试。编译器可以从属性声明中推断出T 的类型,您可以使用@RawRepresentableStorage 对其进行注释。你得到什么编译器错误?您如何使用产生上述错误的属性包装器?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-03
    相关资源
    最近更新 更多