美文网首页
Swift属性包装器的使用

Swift属性包装器的使用

作者: fantasy028 | 来源:发表于2023-08-14 14:08 被阅读0次

    从Swift5.0开始,Swift引入了属性包装器(propertyWrapper),这应该算是苹果原生应用开发上的一次技术思想的突破吧。即便功能限制性很多,但也为我们解决一些问题带来了方便。比如,我们现在要限制一些数值的取值范围的话,在Objc时代,甚至是Swift早些时候。我们要想要实现这种方法,那么久的在赋值或者取值的过程中进行判断。这从代码上来讲还是侵入性比较强的。但是在Swift5.0引入属性包装器之后,这类问题就得到了解决。下面我们就来一步步了解属性包装器的使用吧。
    为了更好的来讨论,我们先设定一个场景:在一个用户信息系统中,我们要存储用户的基本信息,但是要求用户信息中的年龄字段取值只能在0~120之间,如果年龄大于120则取120,小于0则取0,要求使用的时候要保证数据取值的安全性。这个问题我们应该怎么解决呢?
    在属性包装器概念引入之前,为了数据的安全性我们基本上在每个使用到年龄大地方,都要写一大堆保护性代码,或者调用一个专门的封装函数来进行处理,如果涉及到某些地方用年龄来过滤或做表,可能还存在一些其他更复杂的问题。当然,为了统一,我们可能会写一个如下的方法:

    func fixAge(age: Int) -> Int {
      if age > 120 {
        return 120
      }
      if age < 0 {
        return 0
      }
      return age
    }
    

    在使用的时候通过fixAge(age: )调用来达到数据修正的目的。但是,这是一个好办法么?如果我们从代码侵入性角度来看肯定是不好的。下面,我们用属性包装器来实现:

    @propertyWrapper
    struct AgeWrapper {
        var wrappedValue: Int {
            get {
                return age
            }
            set {
                if newValue > max {
                    age = max
                } else if newValue < min {
                    age = min
                } else {
                    age = newValue
                }
            }
        }
        var age: Int = 0
        var min: Int
        var max: Int
        init(min: Int, max: Int) {
            self.min = min
            self.max = max
        }
    }
    

    接下来,我们再来定义变量age

    @AgeWrapper(min: 0, max: 120) var age: Int
    

    并给一个调用的实例如下:

    print("old value -> \(age)")
    age = 139
    print("new value -> \(age)")
    

    运行代码会得到如下运行结果

    old value -> 0
    new value -> 120
    

    好想,我们在使用的时候,完全没有做任何修正,但是我们前面的目的已经达到了。不仅如此,为了实现对年龄限制的的通用性,我们对属性包装器做如下修改:

    @propertyWrapper
    struct AgeWrapper {
        var wrappedValue: Int {
            get {
                return age
            }
            set {
                age = limitHandle(newValue)
            }
        }
        var age: Int = 0
        var limitHandle: (Int) -> Int
        init(limit handle: @escaping (Int) -> Int) {
            self.limitHandle = handle
        }
    }
    

    并将初始化修改如下:

    @AgeWrapper(limit: { max(0, min($0, 120)) }) var age: Int
    

    继续运行执行结果,我们会发现,执行的结果与之前是一致的。而且这个包函数也变的更灵活了。
    有了一个真实的案例,回过来在看看属性包装器的实现逻辑:

    1. 属性包装器的定义基于一个被@propertyWrapper修饰的struct或class的;
    2. 属性包装起有一个必须实现一个名为wrappedValue的属性;该属性实际负责对真实数据进行修正处理
    3. 在使用定义的属性包装器时,将@属性包装器 放在需要修饰的属性前即可;
    4. 最后就是使用被修饰的变量,只需按照我们正常的使用变量的方式使用即可。

    回过头来想想,属性包装器,对于我们已有的未做数据安全保护的代码,是不是现在要进行数据安全性保护的话,将变得更容易呢?

    相关文章

      网友评论

          本文标题:Swift属性包装器的使用

          本文链接:https://www.haomeiwen.com/subject/ctcqmdtx.html