Swift 4:getter和setter直接在struct或class中

Kev*_*ers 17 swift

我试图想出一种使用属性访问UserDefaults的方法.但是,我陷入困境,因为我无法弄清楚如何使属性动态,可以这么说.

这是通用的想法,我想要的 API :

class AppUserDefaults {
  var username = DefaultsKey<String>("username", defaultValue: "Unknown")
  var age = DefaultsKey<Int?>("age", defaultValue: nil)
}

let props = AppUserDefaults()
props.username = "bla"
print("username: \(props.username)")
Run Code Online (Sandbox Code Playgroud)

但是(当然)不起作用,因为类型DefaultsKey<String>不是String.所以我必须在实现中添加一个value属性DefaultsKey来添加getter和setter,如下所示:

struct DefaultsKey<ValueType> {
  private let key: String
  private let defaultValue: ValueType

  public init(_ key: String, defaultValue: ValueType) {
    self.key = key
    self.defaultValue = defaultValue
  }

  var value: ValueType {
    get {
      let value = UserDefaults.standard.object(forKey: key)
      return value as? ValueType ?? defaultValue
    }
    set {
      UserDefaults.standard.setValue(newValue, forKey: key)
      UserDefaults.standard.synchronize()
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

然后像这样使用它:

let props = AppUserDefaults()
props.username.value = "bla"
print("username: \(props.username.value)")
Run Code Online (Sandbox Code Playgroud)

但我觉得这很难看.我也尝试了一个下标方法,但是你仍然需要添加[]而不是.value:

struct DefaultsKey<ValueType> {
  ...
  subscript() -> ValueType {
    get {
      let value = UserDefaults.standard.object(forKey: key)
      return value as? ValueType ?? defaultValue
    }
    set {
      UserDefaults.standard.setValue(newValue, forKey: key)
      UserDefaults.standard.synchronize()
    }
  }
}

let props = AppUserDefaults()
props.username[] = "bla"
print("username: \(props.username[])")
Run Code Online (Sandbox Code Playgroud)

基本上我想要的是我可以直接定义getter和setter DefaultsKey而不必通过该value属性.这对Swift来说根本不可能吗?是否有另一种方法来获取我想要的行为,其中定义的属性AppUserDefaults是"动态的"并通过getter和setter,而不必在内部的属性声明中定义它AppUserDefaults

我希望我在这里使用正确的术语,并为每个人提出明确的问题.

Mih*_*atu 5

我唯一能想到的是:

struct DefaultsKey<ValueType> {
  private let key: String
  private let defaultValue: ValueType

  public init(_ key: String, defaultValue: ValueType) {
    self.key = key
    self.defaultValue = defaultValue
  }

  var value: ValueType {
    get {
      let value = UserDefaults.standard.object(forKey: key)
      return value as? ValueType ?? defaultValue
    }
    set {
      UserDefaults.standard.setValue(newValue, forKey: key)
      UserDefaults.standard.synchronize()
    }
  }
}

class AppUserDefaults {
  private var _username = DefaultsKey<String>("username", defaultValue: "Unknown")
  var username: String {
    set {
      _username.value = newValue
    },
    get {
      return _username.value
    }
  }
}

let props = AppUserDefaults()
props.username = "bla"
print("username: \(props.username)")
Run Code Online (Sandbox Code Playgroud)