type
status
date
slug
summary
tags
category
icon
password
example-row
example-row
闭包是自包含的函数代码块,可以在代码中被传递和使用。Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他一些编程语言中的匿名函数(Lambdas)比较相似。
- 闭包可以捕获和存储其所在上下文中任意常量和变量的引用。
- 全局函数是一个有名字但不会捕获任何值的闭包。
- 嵌套函数是一个有名字并可以捕获其封闭函数域内值的闭包。
- 闭包表达式是一个利用轻量级语法所写的可以捕获其上下文中变量或常量值的匿名闭包。
闭包表达式
闭包表达式是一种在简短行内就能写完闭包的语法。闭包表达式语法能够使用常量形式参数、变量形式参数和输入输出形式参数,但不能 提供默认值。可变形式参数也能使用,但需要在形式参数列表的最后面使用。元组也 可被用来作为形式参数和返回类型。
函数对比闭包表达式
- 函数的功能使用闭包表达式也完全可以实现。
- 函数有的元素,闭包表达式也都有,只是书写方式不一样。
- 注意in是用来分割函数类型和函数体的。
- 闭包表达式需要使用{}来包含进去。
- 如果需要赋给一个变量,就通过变量来调用,如果直接使用,就直接调用传值。
- 与函数不同的是闭包中不用写参数标签,也可以在调用时不写参数名称。
简写闭包表达式
闭包表达式是一种构建内联闭包的方式,它的语法简洁。在保证不丢失它语法清晰明了的同时,闭包表达式提供了几种优化的语法简写形式。下面通过对
sorted(by:)
这一个案例的多次迭代改进来展示这个过程。- 提供排序闭包函数的一种方式是撰写一个符合其类型要求的普通函数,并将其作为 sorted(by:) 方法的参数传入
backward(
:
:)
函数改为对应的闭包表达式版本。
- 因为排序闭包函数是作为
sorted(by:)
方法的参数传入的,Swift 可以推断其参数和返回值的类型。sorted(by:)
方法被一个字符串数组调用,因此其参数必须是(String, String) -> Bool
类型的函数。这意味着(String, String)
和Bool
类型并不需要作为闭包表达式定义的一部分。因为所有的类型都可以被正确推断,返回箭头(->
)和围绕在参数周围的括号也可以被省略。
- 单行表达式闭包可以通过省略
return
关键字来隐式返回单行表达式的结果。
- Swift 自动为内联闭包提供了参数名称缩写功能,可以直接通过
$0
,$1
,$2
来顺序调用闭包的参数,所以参数名称可以使用缩写代替。
- Swift 的
String
类型定义了关于大于号(>
)的字符串实现,其作为一个函数接受两个String
类型的参数并返回Bool
类型的值。而这正好与sorted(by:)
方法的参数需要的函数类型相符合。因此,你可以简单地传递一个大于号,Swift 可以自动推断找到系统自带的那个字符串函数的实现。
尾随闭包
尾随闭包是一个书写在函数圆括号之后的闭包表达式,函数支持将其作为最后一个参数调用。在使用尾随闭包时,不用写出它的参数标签。
上面
sorted(by:)
方法用尾随闭包的写法:如果闭包表达式是函数或方法的唯一参数,则当你使用尾随闭包时,你甚至可以把
()
省略掉。如果一个函数接受多个闭包,您需要省略第一个尾随闭包的参数标签,并为其余尾随闭包添加标签。
当您调用上面函数以加载图片时,需要提供两个闭包。第一个闭包是一个完成处理程序,它在成功下载后加载图片;第二个闭包是一个错误处理程序,它向用户显示错误。通过这种方法编写函数,能够把负责处理网络故障的代码和成功下载后更新用户界面的代码干净地区分开,而不是只使用一个闭包处理两种情况。
值捕获
闭包可以在其被定义的上下文中捕获常量或变量。即使定义这些常量和变量的原作用域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。可以捕获值的闭包的最简单形式是嵌套函数。
上面示例代码中,
incrementer()
函数并没有任何参数,但是在函数体内访问了 runningTotal
和 amount
变量。这是因为它从外围函数捕获了 runningTotal
和 amount
变量的引用。捕获引用保证了 runningTotal
和 amount
变量在调用完 makeIncrementer
后不会消失,并且保证了在下一次执行 incrementer
函数时,runningTotal
依旧存在。- 为了优化,如果一个值不会被闭包改变,或者在闭包创建后不会改变,Swift 可能会改为捕获并保存一份对值的拷贝。
- Swift 也会负责被捕获变量的所有内存管理工作,包括释放不再需要的变量。
- 如果将闭包赋值给一个类实例的属性,并且该闭包通过访问该实例或其成员而捕获了该实例,闭包和该实例间会行成循环强引用。
- 闭包是引用类型,如果你将闭包赋值给了两个不同的常量或变量,两个值都会指向同一个闭包。
逃逸闭包
当一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,我们称该闭包从函数中逃逸。
- 在参数名之前标注
@escaping
,用来指明这个闭包是允许“逃逸”出这个函数。
- 将一个闭包标记为
@escaping
必须在闭包中显式地引用self
。
- 逃逸闭包需要在使用该逃逸闭包的函数返回后,显式的调用才会被执行。
自动闭包
自动闭包是一种自动创建的闭包,用于包装传递给函数作为参数的表达式。
- 不接受任何参数。
- 被调用时,返回被包装在其中的表达式的值。
- 通过给函数的闭包参数标记
@autoclosure
,函数调用的位置的传参使用具体闭包返回的数据类型,而不是闭包。
- 作者:黄x黄
- 链接:https://hxhowl.site/article/swift012
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章