美文网首页
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-闭包

    Swift 闭包 函数 ()->() Swift 中的闭包和 Objective-C 中的 block 类似,闭包...

  • Swift闭包和函数

    函数在Swift中只是一种特殊的闭包,闭包在Swift语言中是一等公民,支持闭包嵌套和闭包传递。Swift中的闭包...

  • swift4 闭包

    swift 闭包 闭包:swift 中 函数是闭包的一种类似于oc的闭包闭包表达式(匿名函数) -- 能够捕获上下...

  • Swift中的闭包

    在Swift中有两种闭包,逃逸闭包(@escaping)和非逃逸闭包(@nonescaping)。从Swift 3...

  • 100 Days of Swift - Day 06 - 闭包(

    100 Days of Swift - Day 06 - 闭包Closures 6.1 闭包 Swift函数也属于...

  • swift学习

    * 闭包 * 闭包作为属性 ```swift // 声明闭包类型 typealias callba...

  • iOS swift 逃逸闭包(@escaping)和非逃逸闭

    iOS swift 逃逸闭包(@escaping)和非逃逸闭包 (@noescaping) 逃逸闭包: 逃逸闭包...

  • iOS&Swift&OC 闭包和Block的相互转化

    一、Swift的闭包 -> OC的block 二、OC的block -> Swift的闭包

  • swift闭包学习

    闭包作为参数 参考 Swift学习之闭包

  • Swift学习笔记(1)

    SWift学习笔记 闭包 闭包表达式 闭包是自包含的函数代码块,可以在代码中被传递和使用。Swift 中的闭包与 ...

网友评论

      本文标题:Swift 闭包

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