5.5 后置闭包、逃逸闭包与自动闭包

闭包常常会作为函数的参数来使用,函数在调用时,参数是写在小括号中的参数列表中的,而闭包又是一个写在大括号中的代码块,如此的嵌套写法在视觉上十分不直观。因此,Swift语言中提供了后置闭包的写法。当函数中的最后一个参数为闭包参数时,在调用函数时,开发者可以将闭包结构脱离出函数的参数列表,追加在函数的尾部,增强代码的可读性,示例如下:

        //原结构
        mySort(array: &stuArr, sortClosure: {
        (stuArr[$0] as! Student).achievement > (stuArr[$1] as! Student).achievement
        })
        //后置闭包结构
        mySort(array: &stuArr){
        (stuArr[$0] as! Student).achievement > (stuArr[$1] as! Student).achievement
        }

后置闭包的语法简化了代码的结构,这里面还有一个小技巧,如果一个函数只有一个参数,且这个参数是一个闭包类型的参数,则开发者在调用函数时,使用后置闭包的写法可以直接将函数的参数列表省略,示例代码如下:

        //只有一个闭包参数的函数
        func myFunc(closure:(Int, Int)->Bool) {
        }
        //进行闭包的后置 可以省略参数列表
        myFunc {
            $0>$1
        }

以上示例代码几乎是闭包的最简形式了。

当闭包传递进函数时,系统会为此闭包进行内存的分配。在Swift语言中,还有逃逸闭包与非逃逸闭包这样的概念。所谓逃逸闭包是指函数内的闭包在函数执行结束后在函数外依然可以进行使用,非逃逸闭包是指当函数的生命周期结束后,闭包也将被销毁。换句话说,非逃逸闭包只能在函数内部使用,在函数外部不能够使用。默认情况下函数参数中的闭包都为非逃逸闭包,这样做的优点是可以提高代码性能,节省内存消耗,开发者可以根据实际需求将闭包参数声明成逃逸闭包。

非逃逸闭包也不可以作为返回值返回,如果这么做,编译器会抛出一个错误。

将闭包声明为非逃逸类型,需要使用@noescape修饰,需要注意,在最新版本的Xcode开发工具中,这个关键字已经不需要再使用,参数中的闭包默认都是非逃逸的,示例代码如下:

        //只有一个闭包参数的函数,将此闭包声明为非逃逸的,此闭包不可作为返回值返回,也不可赋值给外部变量
        //在Xcode8.1中会有警告,这个关键字可以省略
        func myFunc(closure: @noescape (Int, Int)->Bool){
        }

逃逸类型的闭包常用于异步操作中,例如一个后台请求完成后要执行闭包回调,需要使用逃逸类型。

不是所有的闭包都需要显式创建,Swift语言中还有一种语法,其可以实现对简单闭包的自动生成,这种闭包通常称为自动闭包。需要注意,自动闭包参数的使用有严格的条件,首先此闭包不能够有参数,其次在调用函数传参时,此闭包的实现只能由一句表达式组成,闭包的返回值即为此表达式的值,自动闭包参数由@autoclosure来声明,示例代码如下:

        //将闭包参数声明为自动闭包
        func myFunc2(closure: @autoclosure ()->Bool)  {
        }
        //调用函数时,直接传入一个表达式即可,编译器会自动生成闭包参数
        myFunc2(1+2+3>10)

自动闭包默认为非逃逸的,若要使用逃逸类型的闭包参数,需要声明如下:

        //将闭包参数声明为自动闭包 逃逸闭包
        func myFunc2(closure: @autoclosure @escaping ()->Bool)  {
        }