目录:

  • 基本语法
  • 尾随闭包
  • 值捕获
  • 自动闭包

闭包是自包含的函数代码块,闭包采取如下三种形式之一:

  1. ・全局函数是一个有名字但不会捕获任何值的闭包
  1. ・嵌套函数是一个有名字并可以捕获其封闭函数域内值的闭包
  1. ・闭包表达式是一个利用轻量级语法所写的可以捕获其上下文中变量或常量值的匿名闭包

使用简洁的闭包表达式具有以下优点:

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

函数和闭包都是引用类型。

基本语法
  1. { (parameters) -> returnType in
  2. statements
  3. }
  1. (1). 闭包表达式参数可以是in-out参数,但不能设定默认值
  1. (2). 闭包表达式参数可以使用具体名称的可变参数
  1. (3). 可以使用元组作为闭包表达式的参数和返回值
  1. // 内联闭包
  2. reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
  3. return s1 > s2
  4. })
  5.  
  6. // 简写方式
  7. reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } )
  8.  
  9. // 内联闭包表达式构造的闭包作为参数传递给函数或方法时,总是能够推断出闭包的参数和返回值类型。
  10. // 这意味着闭包作为函数或者方法的参数时,可以不用完整格式构造内联闭包
  11. reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )
  12.  
  13. // 单行表达式闭包可以通过省略 return 关键字来隐式返回单行表达式的结果
  14. reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
  15.  
  16. // Swift自动为内联闭包提供参数名称缩写功能,可以使用 $0,$1,$2等来顺序调用闭包参数
  17. reversedNames = names.sorted(by: { $ > $ } )
  18.  
  19. // 运算符方法,String的运算符>刚好接收两个String入参返回Bool结果,可以简写成
  20. reversedNames = names.sorted(by: >)
尾随闭包

如果闭包表达式作为函数最后一个参数,可以使用书写在函数括号之外的省略闭包表达式参数标签的尾随闭包来增强函数的可读性。

  1. func someFunctionThatTakesAClosure(closure: () -> Void) {
  2. // 函数体部分
  3. }
  4.  
  5. // 内联闭包进行函数调用
  6. someFunctionThatTakesAClosure(closure: {
  7. // 闭包主体部分
  8. })
  9.  
  10. // 尾随闭包进行函数调用
  11. someFunctionThatTakesAClosure() {
  12. // 闭包主体部分
  13. }
  14.  
  15. reversedNames = names.sorted() { $ > $ }
  16.  
  17. // 如果闭包表达式作为函数或方法的唯一参数,则使用尾随闭包时,可以省略()
  18. reversedNames = names.sorted { $ > $ }
值捕获

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

  1. // makeIncrementer执行完后,runningTotal的作用域不存在了,
  2. // 但调用返回的函数时依然能够改变和访问runningTotal的值
  3. func makeIncrementer(forIncrement amount: Int) -> () -> Int {
  4. var runningTotal =
  5. func incrementer() -> Int {
  6. runningTotal += amount
  7. return runningTotal
  8. }
  9. return incrementer
  10. }
  11.  
  12. let incrementByTen = makeIncrementor(forIncrement: )
  13.  
  14. // 闭包是引用类型,将闭包同时赋值给两个变量或常量,这两个变量或常量指向同一个闭包
  15. let alsoIncrementByTen = incrementByTen
逃逸闭包

当一个闭包作为函数参数传入,但在函数执行返回之后才被执行,称该闭包为逃逸闭包。可以使用 @escaping 在参数前标注闭包为逃逸闭包,用来指明这个闭包是允许“逃逸”出这个函数的。

异步处理操作通常需要传入一个可以逃逸的闭包作为complete callback,这时往往将传入的闭包保存在函数外部定义的变量中。

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

将一个闭包标记为 @escaping 意味着你必须在闭包中显式地引用 self。

  1. func someFunctionWithNonescapingClosure(closure: () -> Void) {
  2. closure()
  3. }
  4.  
  5. class SomeClass {
  6. var x =
  7. func doSomething() {
  8. someFunctionWithEscapingClosure { self.x = }
  9. someFunctionWithNonescapingClosure { x = }
  10. }
  11. }
  12. let instance = SomeClass() instance.doSomething() print(instance.x) // 打印出 "200"
  13. completionHandlers.first?() print(instance.x) // 打印出 "100"
自动闭包

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

  1. var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
  2. print(customersInLine.count) // 打印出 "5"
  3. let customerProvider = { customersInLine.remove(at: ) }
  4. print(customersInLine.count) // 打印出 "5"
  5. print("Now serving \(customerProvider())!") // Prints "Now serving Chris!"
  6. print(customersInLine.count) // 打印出 "4"

通过将参数标记为 @autoclosure 来接收一个自动闭包。下面serve()以自动闭包做函数参数可以视为接受String类型参数(而非闭包)的函数来调用。

  1. // customersInLine is ["Ewa", "Barry", "Daniella"]
  2. func serve(customer customerProvider: @autoclosure () -> String) {
  3. print("Now serving \(customerProvider())!")
  4. }
  5. serve(customer: customersInLine.remove(at: )) // 打印 "Now serving Ewa!"

如果像让一个自动闭包可以“逃逸”,则应该同时使用 @autoclosure 和 @escaping 属性。

  1. // customersInLine i= ["Barry", "Daniella"]
  2. var customerProviders: [() -> String] = []
  3. func collectCustomerProviders(_ customerProvider: @autoclosure @escaping () -> String) {
  4. customerProviders.append(customerProvider)
  5. }
  6. collectCustomerProviders(customersInLine.remove(at: ))
  7. collectCustomerProviders(customersInLine.remove(at: ))
  8. print("Collected \(customerProviders.count) closures.") // 打印 "Collected 2 closures."
  9. for customerProvider in customerProviders {
  10. print("Now serving \(customerProvider())!")
  11. }
  12. // 打印 "Now serving Barry!"
  13. // 打印 "Now serving Daniella!"
声明:该系列内容均来自网络或电子书籍,只做学习总结!

Swift学习笔记(8):闭包的更多相关文章

  1. Swift学习笔记之闭包

    简介 (真的很简) 闭包的完整形态是这个样子的: { (parameters) -> returnType in statements } 写在一行里就是这样: {(parameters) -& ...

  2. Swift学习笔记(9)--闭包

    1.闭包表达式: { (parameters) -> returnType in statements } 注1.闭包表达式语法可以使用常量.变量和inout类型作为参数,不提供默认值. 也可以 ...

  3. swift学习笔记之-闭包

    //闭包 import UIKit /*闭包(Closures): 函数.闭包.类都是引用类型(引用类型的实例赋值给变量或常量时,得到的都是该实例的引用,而值类型的实例变量得到的是独立的值的拷贝) 1 ...

  4. 【swift学习笔记】二.页面转跳数据回传

    上一篇我们介绍了页面转跳:[swift学习笔记]一.页面转跳的条件判断和传值 这一篇说一下如何把数据回传回父页面,如下图所示,这个例子很简单,只是把传过去的数据加上了"回传"两个字 ...

  5. Swift学习笔记(一)搭配环境以及代码运行成功

    原文:Swift学习笔记(一)搭配环境以及代码运行成功 1.Swift是啥? 百度去!度娘告诉你它是苹果最新推出的编程语言,比c,c++,objc要高效简单.能够开发ios,mac相关的app哦!是苹 ...

  6. swift学习笔记2——函数、闭包

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

  7. Swift学习笔记一

    最近计划把Swift语言系统学习一下,然后将MagViewer用这种新语言重构一次,并且优化一下,这里记录一下Swift的学习笔记. Swift和Objective-C相比,在语法和书写形式上做了很多 ...

  8. 记录:swift学习笔记1-2

    swift还在不断的更新做细微的调整,都说早起的鸟儿有虫吃,那么我们早点出发吧,趁着国内绝大多数的coder们还没有开始大范围普遍应用. 网上有些大神说:swift很简单!我不同意这个观点,假如你用h ...

  9. swift学习笔记5——其它部分(自动引用计数、错误处理、泛型...)

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

  10. swift学习笔记4——扩展、协议

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

随机推荐

  1. java.lang.ClassNotFoundException: org.objectweb.asm.ClassWriter

    转自:https://www.cnblogs.com/yfceshi/p/6814802.html Caused by: javax.xml.ws.WebServiceException: java. ...

  2. HTML iframe 和 frameset 的区别

    转自:http://www.cnblogs.com/polk6/archive/2013/05/24/3097430.html HTML iframe 和 frameset 的区别 iframe 和 ...

  3. maven的pom.xml配置标签

    转自:https://blog.csdn.net/wf787283810/article/details/76188595 <project xmlns="http://maven.a ...

  4. MVC、控件、一般处理程序中的session and cookie

    Mvc中: session: if (!string .IsNullOrEmpty(find)) //设置 Session["oip"] = "无锡"; Vie ...

  5. AVL数

    平衡二叉树(AVL树) AVL树是一种二叉搜索树,并且每个节点的左右子树高度之差最多为1.AVL树是第一个在最坏的情况下保证以O(logn)的时间进行搜索,插入和删除操作的数据结构,AVL树能在对数时 ...

  6. 服务端 | Linux 学习总结 (一)

    http://billie66.github.io/TLCL/book/ 1.Ubuntu && linux shell 命令 Ubuntu两个重要版本:12.04和14.04 在终端 ...

  7. Android中的事件分发机制

    Android中的事件分发机制 作者:丁明祥 邮箱:2780087178@qq.com 这篇文章这周之内尽量写完 参考资料: Android事件分发机制完全解析,带你从源码的角度彻底理解(上) And ...

  8. Golden Gate 相关组件介绍:

    OGG组件: Manager: 启动其它进程 Collector Extract Data Pump:可选进程,建议使用 Replicat Trails: 可以压缩,加密 Checkpoint OGG ...

  9. UIView 绘制渲染机制

    #前言 APP页面优化对小编来说一直是难题,最近一直在不断的学习和总结 ,发现APP页面优化说到底离不开view的绘制和渲染机制.网上有很多精彩的博客,小编借鉴之前N多大牛研究成果,同时结合自己遇到的 ...

  10. css 书写推荐顺序

    1.位置属性(position, top, right, z-index, display, float等)2.大小(width, height, padding, margin)3.文字系列(fon ...