【问题标题】:Use Swift @propertyWrapper for dynamic default value?使用 Swift @propertyWrapper 作为动态默认值?
【发布时间】:2019-11-18 20:22:27
【问题描述】:

我需要一个 Swift 属性——如果该值尚未设置——默认为另一个值。

这个可以使用后备存储私有属性来实现。例如,对于应该默认为全局 defaultNum 的属性 num,它的工作方式如下:

var defaultNum = 1

class MyClass {
  var num: Int {
    get { _num ?? defaultNum }
    set { _num = newValue }
   }

  private var _num: Int?
}

let c = MyClass()
print("initial \(c.num)") // == 1 ✅

// changing the default changes the value returned
defaultNum = 2
print("dynamic \(c.num)") // == 2 ✅

// once the property is set, returns the stored value
c.num = 5
print("base    \(c.num)") // == 5 ✅

这可行,但对于我们代码中的一个常见模式,每个此类属性都有很多样板文件。

使用 Swift 属性包装器,是否可以更简洁地做到这一点?


什么行不通

请注意,因为我们希望默认值是动态的,所以静态初始化器将不起作用。例如:

var defaultNum = 1

class MyClass {
  var num = defaultNum
}

var c = MyClass()
defaultNum = 2
print(c.num) // this == 1, we want the current value of defaultNum, which == 2

【问题讨论】:

    标签: swift swift5.1 property-wrapper


    【解决方案1】:

    您可以通过创建这样的属性包装器来做到这一点:

    @propertyWrapper
    public struct Default<T> {
      var baseValue: T?
      var closure: () -> T
    
      // this allows a nicer syntax for single variables...
      public init(_ closure: @autoclosure @escaping () -> T) {
        self.closure = closure
      }
    
      // ... and if we want to explicitly use a closure, we can.
      public init(_ closure: @escaping () -> T) {
        self.closure = closure
      }
    
      public var wrappedValue: T {
        get { baseValue ?? closure() }
        set { baseValue = newValue }
      }
    }
    

    然后,您可以在这样的属性上使用 @Default 属性包装器:

    var defaultNum = 1
    
    class MyClass {
      @Default(defaultNum)
      var num: Int
    }
    

    然后您会在实践中看到以下内容:

    let c = MyClass()
    
    // if we haven't set the property yet, it uses the closure to return a default value
    print("initial \(c.num)") // == 1 ✅
    
    // because we are using a closure, changing the default changes the value returned
    defaultNum = 2
    print("dynamic \(c.num)") // == 2 ✅
    
    // once the property is set, uses the stored base value
    c.num = 5
    print("base    \(c.num)") // == 5 ✅
    

    【讨论】:

      猜你喜欢
      • 2021-10-08
      • 2015-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-05
      • 1970-01-01
      • 1970-01-01
      • 2017-01-07
      相关资源
      最近更新 更多