@autoclosure及自动封装成闭包
我们先模拟一个场景 创建一个数组 我们先判断数组是否为空,再去判断他下标为0的元素是否为0
显然这段场景需要先执行第一步才能再执行第二步 否则数组会出现越界
我们使用下面代码
let num = [Int]()
//这里第一个条件判断出有问题就不会执行第二个操作了 这样就不会越界了
if !num.isEmpty && num[0]>0{
}
这里是没有问题的
现在我们想设置一个函数 ,来代替&&的操作
func judgeTwice ( a : Bool , b : @autoclosure ()-> Bool) -> Bool{
func judgeTwice (_ a : Bool ,_ b :Bool) -> Bool{
print("judgeTwice start working")
guard a else {
return false
}
return b
}
if judgeTwice(!num.isEmpty,num[0]>0) {
}
这里就报错了 原因是num[0]>0在执行第一个!num.isEmpty参数的情况下就被执行了,控制台也没有打印消息,说明这个函数并没有被调用就已经崩溃了 。
我们可以得出结论函数使用的时候系统先去会编译一次函数的参数,去看其是否越界之类。
如果想要参数在函数中再去执行,我们就可以使用闭包的方法,把条件封装起来,不然系统检查到越界,因为我们在函数中可以保证使用的时候不会出现越界问题。
我们修改一下上面代码
func judgeTwice (_ a : Bool ,_ b :()-> Bool) -> Bool{
print("judgeTwice start working")
guard a else {
return false
}
return b()
}
//这里我们要把参数封装成一个闭包
if judgeTwice(!num.isEmpty,{return num[0]>0}) {
}
这样系统就不会报错了 而且judgeTwice方法也被调用了
但是每次都要把该参数封装一下 十分麻烦 于是系统帮我们发明了@autoclosure关键字 ,作用就是我们只要把参数放进去系统会自动帮我们封装成闭包。这样就可以达到参数的延迟执行,而且也可以享受延迟执行的性能优化,num[0]>0 变成{return num[0]>0}
上面代码更改成最终模式
func judgeTwice (_ a : Bool ,_ b :@autoclosure ()-> Bool) -> Bool{
print("judgeTwice start working")
guard a else {
return false
}
return b()
}
if judgeTwice(!num.isEmpty,num[0]>0) {
}
这使用起来就会很方便了
还有 系统中一般对函数的参数判断有要求的都会采用闭包,否则的话参数会在调试阶段就被调用一次。
@autoclosure在系统函数中经常看到
比如??运算符,显然这是个二项运算符要传入两个左右参数,
想一下这个场景a??b,显然你不想在a判断是否有值前就去执行一次b操作了把 ,b需要延迟执行,这个延迟条件取决于a。所以系统对这个运算符的右边参数是进行了@autoclosure封装的,延迟执行的重要性体现在假如b里面的操作是涉及引用计数器相关的操作,如果被多执行一次会造成巨大的bug,所以要使用到@autoclosure