从Swift5.0开始,Swift引入了属性包装器(propertyWrapper),这应该算是苹果原生应用开发上的一次技术思想的突破吧。即便功能限制性很多,但也为我们解决一些问题带来了方便。比如,我们现在要限制一些数值的取值范围的话,在Objc时代,甚至是Swift早些时候。我们要想要实现这种方法,那么久的在赋值或者取值的过程中进行判断。这从代码上来讲还是侵入性比较强的。但是在Swift5.0引入属性包装器之后,这类问题就得到了解决。下面我们就来一步步了解属性包装器的使用吧。
为了更好的来讨论,我们先设定一个场景:在一个用户信息系统中,我们要存储用户的基本信息,但是要求用户信息中的年龄字段取值只能在0~之间,如果年龄大于则取,小于0则取0,要求使用的时候要保证数据取值的安全性。这个问题我们应该怎么解决呢?
在属性包装器概念引入之前,为了数据的安全性我们基本上在每个使用到年龄大地方,都要写一大堆保护性代码,或者调用一个专门的封装函数来进行处理,如果涉及到某些地方用年龄来过滤或做表,可能还存在一些其他更复杂的问题。当然,为了统一,我们可能会写一个如下的方法:
funcfixAge(age:Int)-Int{
ifage{
return
}
ifage0{
return0
}
returnage
}
在使用的时候通过fixAge(age:)调用来达到数据修正的目的。但是,这是一个好办法么?如果我们从代码侵入性角度来看肯定是不好的。下面,我们用属性包装器来实现:
propertyWrapperstructAgeWrapper{
varwrappedValue:Int{
get{
returnage
}
set{
ifnewValuemax{
age=max
}elseifnewValuemin{
age=min
}else{
age=newValue
}
}
}
varage:Int=0
varmin:Int
varmax:Int
init(min:Int,max:Int){
self.min=min
self.max=max
}
}
接下来,我们再来定义变量age
AgeWrapper(min:0,max:)varage:Int并给一个调用的实例如下:
print("oldvalue-\(age)")
age=
print("newvalue-\(age)")
运行代码会得到如下运行结果
oldvalue-0
newvalue-
好想,我们在使用的时候,完全没有做任何修正,但是我们前面的目的已经达到了。不仅如此,为了实现对年龄限制的的通用性,我们对属性包装器做如下修改:
propertyWrapperstructAgeWrapper{
varwrappedValue:Int{
get{
returnage
}
set{
age=limitHandle(newValue)
}
}
varage:Int=0
varlimitHandle:(Int)-Int
init(limithandle:
escaping(Int)-Int){self.limitHandle=handle
}
}
并将初始化修改如下:
AgeWrapper(limit:{max(0,min($0,))})varage:Int继续运行执行结果,我们会发现,执行的结果与之前是一致的。而且这个包函数也变的更灵活了。
有了一个真实的案例,回过来在看看属性包装器的实现逻辑:
1.属性包装器的定义基于一个被
propertyWrapper修饰的struct或class的;2.属性包装起有一个必须实现一个名为wrappedValue的属性;该属性实际负责对真实数据进行修正处理
3.在使用定义的属性包装器时,将
属性包装器放在需要修饰的属性前即可;4.最后就是使用被修饰的变量,只需按照我们正常的使用变量的方式使用即可。
回过头来想想,属性包装器,对于我们已有的未做数据安全保护的代码,是不是现在要进行数据安全性保护的话,将变得更容易呢?