vislee / leevis.com

Blog
87 stars 13 forks source link

swift属性包装器 #195

Open vislee opened 11 months ago

vislee commented 11 months ago

概述

写好的一篇提交了,等提交完发现丢了。。。 丢了。。。只能简单回忆记录一下了。

了解属性包装器前先要了解存储属性和计算属性,属性包装器实际上就是对有关系的存储属性和计算属性进行包装。

当需要在存储属性赋值时做一些逻辑,常规的做法是把该存储属性定义为private的,用计算属性封装一层。 例如:需要把属性值限制在小于12,下面是个例子

struct Test {
    private var _x:Int = 0
    var x:Int {
        get {self._x}
        set {self._x = min(12, newValue)}
    }
    private var _y:Int = 0
    var y:Int {
        get {self._y}
        set {self._y = min(12, newValue)}
    }
}

var t = Test()
t.x = 30
print(t.x)

t.y = 3
print(t.y)

输出:

12
3

当还有很多属性都有类似的限制时,我们不能把代码一直复制下去。按照以往经验重复代码我们会抽象成一个函数或者模版类。没错,我们抽象出一个结构体,如下:

struct SmallNumber {
    private var _wrappedValue: Int = 0

    var wrappedValue:Int {
        get {self._wrappedValue}
        set {
            print("---SmallNumber:setter---")
            self._wrappedValue = min(12, newValue)
        }
    }
}

struct Test {
    private var _x = SmallNumber()
    var x:Int {
        get {self._x.wrappedValue}
        set {self._x.wrappedValue = newValue}
    }
    private var _y = SmallNumber()
    var y:Int {
        get {self._y.wrappedValue}
        set {self._y.wrappedValue = newValue}
    }
}

var t = Test()
t.x = 30
print(t.x)

t.y = 3
print(t.y)

输出:

---SmallNumber:setter---
12
---SmallNumber:setter---
3

上述代码我们只是把限制值不大于12抽象在一个结构体了,在实际的结构体里还需要用计算属性封装一层。冗余代码还很多。

实现

swift提供了一种写法 也就是 属性封装器,可以省去编写很多冗余代码,

  1. 使用 @propertyWrapper 修饰抽出去的结构体、类、enum等。
  2. 必须定义名称为 wrappedValue 的计算属性。

@propertyWrapper
struct SmallNumber {
    private var _wrappedValue: Int = 0

    var wrappedValue:Int {
        get {self._wrappedValue}
        set {
            print("---SmallNumber:setter---")
            self._wrappedValue = min(12, newValue)
        }
    }
}

struct Test {
    @SmallNumber var x:Int
    @SmallNumber var y:Int
}

var t = Test()
t.x = 30
print(t.x)

t.y = 3
print(t.y)

@SmallNumber var x:Int 等价于:

    private var _x = SmallNumber()
    var x:Int {
        get {self._x.wrappedValue}
        set {self._x.wrappedValue = newValue}
    }

总结