美文网首页
Swift 闭包

Swift 闭包

作者: 小猪蛋蛋 | 来源:发表于2020-06-30 17:38 被阅读0次

    一个函数和它所捕获的变量\常量环境组合起来,称为闭包

    • 一般指定义在函数内部的函数
    • 一般它捕获的是外层函数的局部变量\常量
      Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)比较相似。

    一、闭包表达式

      闭包表达式是一种构建内联闭包的方式,它的语法简洁。在保证不丢失它语法清晰明了的同时,闭包表达式提供了几种优化的语法简写形式。

    Swift 的闭包表达式拥有简洁的风格,并鼓励在常见场景中进行语法优化,主要优化如下:

    • 利用上下文推断参数和返回值类型
    • 隐式返回单表达式闭包,即单表达式闭包可以省略 return 关键字
    • 参数名称缩写
    • 尾随闭包语法

    1、在Swift中,可以通过func定义一个函数,也可以通过闭包表达式定义一个函数

     func sum(_ v1: Int, _ v2: Int) -> Int { v1 + v2 }
    
    var fn = {
        (v1: Int, v2: Int) -> Int in return v1 + v2
     }
    fn(10, 20)
    

    闭包表达式的语法形式如下:

    {
       (参数列表) -> 返回值类型 in 函数体代码
    }
    

    2、闭包表达式的简写

    以数组的排序方法 sort(by: ) 作为示例
    sort(by: )会基于你提供的排序闭包表达式的判断结果对数组中的值(类型确定)进行排序。

    //定义一个数组
    var arr = [2,4,1,45,23,12,43]
    
    • 以函数形式传入
    func temp(v1: Int, v2: Int) -> Bool {
        return v1 >= v2
    }
    arr.sort(by: temp)
    
    • 以闭包的方式
    //temp函数对应的闭包表达式形式:
        arr.sort { (v1: Int, v2: Int) -> Bool in
            return v1 >= v2
        }
    //根据上下文推断参数类型和返回类型
        arr.sort(by: {v1, v2 in return v1 >= v2})
    //单表达式闭包的隐式返回 单行表达式闭包可以通过省略 return 
        arr.sort(by: {v1, v2  in v1 >= v2 })
    //参数名称缩写 Swift自动为内联闭包提供了参数名称缩写功能,你可以直接通过 $0,$1,$2... 来顺序调用闭包的参数。
        arr.sort(by: {$0 >= $1})
    //运算符方法
        arr.sort(by: >=)
    //尾随闭包 如果将一个闭包表达式作为函数的最后一个参数,使用尾随闭包可以增强可读性
        arr.sort(){$0 >= $1}
    //如果闭包表达式作为函数的唯一实参,并且使用了尾随闭包,则函数名后面的小括号可以省略
        arr.sort{$0 >= $1}
    print(arr)
    

    二、逃逸闭包

      当闭包作为一个实际参数传递给一个函数的时候,并且它会在函数返回之后调用,我 们就说这个闭包逃逸了。当你声明一个接受闭包作为形式参数的函数时,你可以在形 式参数前写 @escaping 来明确闭包是允许逃逸的。
      闭包可以逃逸的一种方法是被储存在定义于函数外的变量里。比如说,很多函数接收 闭包实际参数来作为启动异步任务的回调。函数在启动任务后返回,但是闭包要直到 任务完成——闭包需要逃逸,以便于稍后调用。

    var completionHandlers: [() -> Void] = []
    func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
        completionHandlers.append(completionHandler)
    }
    

      someFunctionWithEscapingClosure() 函数接收一个闭包作为参数,同时该闭包被添加到一个函数外定义的数组中。此时你需要将这个参数标记为 @escaping ,否则将会编译报错。
      让闭包 @escaping 意味着你必须在闭包中显式地引用 self。例如下面代码,传递到someFunctionWithEscapingClosure()的是一个被@escaping标识的逃逸闭包,所以必须要显现的引用self,即必须要写self;而传递到someFunctionWithNonescapingClosure()的是一个非逃逸闭包,所以可以隐式的引用self,即可以不写self。

    func someFunctionWithNonescapingClosure(closure: () -> Void) {
        closure()
    }
    class SomeClass {
        var x = 10
        func doSomething() {
            someFunctionWithEscapingClosure { self.x = 100 }
            someFunctionWithNonescapingClosure { x = 200 }
        }
    }
    let instance = SomeClass()
    instance.doSomething()
    print(instance.x) // 打印出“200”
    completionHandlers.first?()
    print(instance.x) // 打印出“100”
    

    三、自动闭包

    自动闭包让你能够延迟求值,因为直到你调用这个闭包,代码段才会被执行。

    func getNum() -> Int{
        let a = 10
        let b = 11
        print("调用")
        return a + b
    }
    // 如果第1个数大于0,返回第一个数。否则返回第2个数
    func getFirstPositive(v1: Int, v2: Int) -> Int{
        return v1 > 10 ? v1 : v2
    }
    getFirstPositive(v1: 10, v2: getNum())
    
    

      例如上述代码,当调用 getFirstPositive() 函数时,不管传入的v1是否大于10,则都会调用getNum()函数,这样就造成了浪费。当时如果将参数v2改成函数类型的参数,则可以让v2延迟加载

    func getFirstPositive(_ v1: Int, _ v2: () -> Int) -> Int{
        return v1 > 10 ? v1 : v2()
    }
    //getFirstPositive(10, {20})
    //因闭包作为函数的最后一个参数,可以使用尾随闭包
    getFirstPositive(10){20}
    

      通过 @autoclosure 标志标记它的形式参数使用了自动闭包。现在你可以调用函数就像它接收了一个 Int类型的 实际参数而不是闭包。实际参数自动地转换为闭包,因为 customerProvider 形式参数的类型被标记为 @autoclosure 标记。

    func getFirstPositive(_ v1: Int, _ v2: @autoclosure () -> Int) -> Int{
        return v1 > 10 ? v1 : v2()
    }
    //因为使用了@autoclosure进行标记它的形式参数使用了自动闭包,调用的时候不再是//getFirstPositive(10, {20})
    getFirstPositive(10, 20)
    

    注意:

    • 为了避免与期望冲突,使用了@autoclosure的地方最好明确注释清楚:这个值会被推迟执行
    • @autoclosure 会自动将 20 封装成闭包 { 20 }
    • @autoclosure 只支持 () -> T 格式的参数 n@autoclosure 并非只支持最后1个参数
    • 空合并运算符 ?? 使用了 @autoclosure 技术
    • 有@autoclosure、无@autoclosure,构成了函数重载

    如果有什么不对的地方,欢迎指正,大家共同进步

    相关文章

      网友评论

          本文标题:Swift 闭包

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