Swift3.0 闭包(blcok)的全面介绍及使用

闭包是自包含的函数代码块,能够在代码中被传递和使用。Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其余一些编程语言中的匿名函数比较类似。闭包能够捕获和存储其所在上下文中任意常量和变量的引用。被称为包裹常量和变量。 Swift 会为你管理在捕获过程当中涉及到的全部内存操做。编程

闭包表达式语法有以下的通常形式:swift

{
    (parameters) -> returnType in
      statements
 }
  • 这里的参数(parameters),能够是in-out(输入输出参数),但不能设定默认值。若是是可变参数,必须放在最后一位,否则编译器报错。元组也能够做为参数或者返回值。
  • 闭包的函数体部分由关键字in引入。该关键字表示闭包的参数和返回值类型定义已经完成,闭包函数体即将开始

例如:api

let  sum:(Int , Int) -> Int = {(a : Int ,b : Int) -> Int in
          return a + b  
}
 print(sum(3,4))

因为能够推断出闭包的参数和返回值类型,因此闭包表达式能够表达为:闭包

let  sum:( Int , Int ) -> Int = { a , b  in
          return a + b 
 }

 

单表达式闭包隐式返回编程语言

单行表达式闭包能够经过省略 return 关键字来隐式返回单行表达式的结果,如上版本的例子能够改写为: ide

let  sum:( Int , Int ) -> Int = { a , b  in
          a + b 
 }

有参数没有返回值的写法函数

let say0:(String) ->Void = {
    (name: String) in
    print("hi \(name)")
}
say0("cdh")
//输出结果:  hi cdh

没有参数没有返回值写法优化

let say1:() ->Void = {
    () -> () in // 当没有参数也没有返回值是这行均可以省略
    print("hi cdh")
}
say1()
//输出结果:  hi cdh

闭包的声明spa

Swift用typealias声明闭包数据类型,相似于Objective-C中的typedefcode

typealias  TestBlcok = (Int , Int) -> Int

let test : TestBlcok = {( a , b ) in  a + b}

let result = test( 12 , 20 )

计算结果是 32

 尾随闭包

若将闭包做为函数最后一个参数,能够省略参数标签,而后将闭包表达式写在函数调用括号后面

func testFunction(testBlock: ()->Void){
    //这里须要传进来的闭包类型是无参数和无返回值的
    testBlock()
}
//正常写法
testFunction(testBlock: {
    print("正常写法")
})
//尾随闭包写法
testFunction(){
    print("尾随闭包写法")
}
//也能够把括号去掉,也是尾随闭包写法。推荐写法
testFunction { 
    print("去掉括号的尾随闭包写法")
}

 值捕获

闭包能够在其被定义的上下文中捕获常量或变量。即便定义这些常量和变量的原做用域已经不存在,闭包仍然能够在闭包函数体内引用和修改这些值。

Swift 中,能够捕获值的闭包的最简单形式是嵌套函数,也就是定义在其余函数的函数体内的函数。嵌套函数能够捕获其外部函数全部的参数以及定义的常量和变量。”

 例如:

func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}

makeIncrementor 返回类型为 () -> Int。这意味着其返回的是一个函数,而非一个简单类型的值。该函数在每次调用时不接受参数,只返回一个 Int 类型的值。

makeIncrementer(forIncrement:) 函数定义了一个初始值为 0 的整型变量 runningTotal,用来存储当前总计数值。该值为 incrementor 的返回值。

makeIncrementer(forIncrement:) 有一个 Int 类型的参数,其外部参数名为 forIncrement,内部参数名为 amount,该参数表示每次 incrementor 被调用时 runningTotal 将要增长的量。makeIncrementer 函数还定义了一个嵌套函数 incrementor,用来执行实际的增长操做。该函数简单地使 runningTotal 增长 amount,并将其返回。

若是咱们单独考虑嵌套函数 incrementer(),会发现它有些不一样寻常:

func incrementer() -> Int {
    runningTotal += amount
    return runningTotal
}

 incrementer() 函数并无任何参数,可是在函数体内访问了 runningTotal 和 amount 变量。这是由于它从外围函数捕获了 runningTotal 和 amount 变量的引用。捕获引用保证了 runningTotal 和 amount 变量在调用完 makeIncrementer 后不会消失,而且保证了在下一次执行 incrementer 函数时,runningTotal 依旧存在。

注意 :为了优化,若是一个值不会被闭包改变,或者在闭包建立后不会改变,Swift 可能会改成捕获并保存一份对值的拷贝。 Swift 也会负责被捕获变量的全部内存管理工做,包括释放再也不须要的变量。

闭包引发的循环强引用 

//定义一个全局变量:

        var a: Int = 9

        var closure: ()->Void = {

            /**

             默认闭包会对它访问的对象执行强引用。
             这个地方访问了self ,致使调用 该闭包的时候引用计数+1
             若是闭包属性中没有直接或者间接访问self,就不会产生循环强引用。
             可使用unowned或者weak 来修饰self。
             固然两种存在区别。Swift中的weak、unowned对应Objective-C中的weak、unsafe_unretained,
             这代表前者在对象释放后 会自动将对象置为nil,然后者依然保持一个“无效的”引用,若是此时调用这
             个“无效的”引用将会引发程序崩溃。对于后者的使用,咱们必须保证访问的时候对象没有释放。
             相反,weak则友好一点咱们也更加习惯使用它,

             */

       [weak self] in

       print("a=\(self.a)")

}

逃逸闭包

当一个闭包做为参数传到一个函数中,可是这个闭包在函数返回以后才被执行,咱们称该闭包从函数中逃逸。当你定义接受闭包做为参数的函数时,你能够在参数名以前标注 @escaping,用来指明这个闭包是容许“逃逸”出这个函数的。

自动闭包

自动闭包是一种自动建立的闭包,用于包装传递给函数做为参数的表达式。这种闭包不接受任何参数,当它被调用的时候,会返回被包装在其中的表达式的值。这种便利语法让你可以省略闭包的花括号,用一个普通的表达式来代替显式的闭包。

自动闭包让你可以延迟求值,由于直到你调用这个闭包,代码段才会被执行。延迟求值对于那些有反作用(Side Effect)和高计算成本的代码来讲是颇有益处的,由于它使得你能控制代码的执行时机。

相关文章
相关标签/搜索