目录:

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

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

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

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

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

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

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

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

func someFunctionThatTakesAClosure(closure: () -> Void) {
// 函数体部分
} // 内联闭包进行函数调用
someFunctionThatTakesAClosure(closure: {
// 闭包主体部分
}) // 尾随闭包进行函数调用
someFunctionThatTakesAClosure() {
// 闭包主体部分
} reversedNames = names.sorted() { $ > $ } // 如果闭包表达式作为函数或方法的唯一参数,则使用尾随闭包时,可以省略()
reversedNames = names.sorted { $ > $ }
值捕获

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

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

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

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

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

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

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

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

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

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

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

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

// customersInLine i= ["Barry", "Daniella"]
var customerProviders: [() -> String] = []
func collectCustomerProviders(_ customerProvider: @autoclosure @escaping () -> String) {
customerProviders.append(customerProvider)
}
collectCustomerProviders(customersInLine.remove(at: ))
collectCustomerProviders(customersInLine.remove(at: ))
print("Collected \(customerProviders.count) closures.") // 打印 "Collected 2 closures."
for customerProvider in customerProviders {
print("Now serving \(customerProvider())!")
}
// 打印 "Now serving Barry!"
// 打印 "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. PHP 导出excel 数据量大时

    public function ceshiexcel1(){ set_time_limit(0); $filename = '病毒日志'; header('Content-Type: applicat ...

  2. PHP函数十进制、二进制、八进制和十六进制转换函数说明

    1.十进制转二进制 decbin() 函数,如下实例  echo decbin(12); //输出 1100 echo decbin(26); //输出 11010 2.十进制转八进制 decoct( ...

  3. c#可自定义码表的base64加密解密算法类

    000 using System; using System.Collections.Generic; using System.Linq; using System.Text; using Syst ...

  4. 杭电 2817 A sequence of numbers【快速幂取模】

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2817 解题思路:arithmetic or geometric sequences 是等差数列和等比数 ...

  5. CDR实例教程-高考789,敢拼就能赢!

    本教程是我去年做的一个案例,本来今年想要在做一个,突然意识到今天就是高考日了,没来的及,所以大家将就看些.7.8.9是值得一生纪念的日子,也是以后的每年都会怀念的日子,因为是全国都在上演史诗大剧“决战 ...

  6. Java语言特点与学习

    Java语言是一款面向对象的一款高级语言是由Sun Microsystems公司(现已被oracle公司收购).由James Gosling和同事们共同研发,并在1995年正式推出,据oracle官方 ...

  7. Settings Django Static Files

    静态文件是通过django.contrib.staticfiles来管理的. 配置Django静态文件,Djang官网静态文件配置介绍.简言之,通过以下三个步骤来配置和加载静态文件: 设置静态文件别名 ...

  8. docker 镜像的导入导出

    今天使用docker部署asp.net core应用程序时,发现当我们做好基础镜像之后需要把镜像导出到正式环境,因此学习了一下如何从docker中导出镜像: 1.首先通过docker images命令 ...

  9. SUSE Linux Enterprise 11 SP4系统安装过程 字符界面

    首先开启虚拟机之后显示这个界面: (1) 进入之后显示下面界面,点击Installation安装. (2)进入Welcome界面,选择语言,默认Einglish(US)不需要改动:点击I Agree ...

  10. mkl安装与使用

    mkl安装教程 1.下载 首先到该网站下载压缩包,需要注册 2.安装 首先解压缩 tar -zxvf l_mkl_2019.0.117.tgz 进入目录进行安装 cd l_mkl_2019.0.117 ...