学习swift从青铜到王者之swift闭包06
语法表达式
一般形式:{
(parameters) -> returnType in
statements
}
这里的参数(parameters),可以是in-out(输入输出参数),但不能设定默认值。如果是可变参数,必须放在最后一位,不然编译器报错。元组也可以作为参数或者返回值。
"in"关键字表示闭包的参数和返回值类型定义已经完成,闭包函数体即将开始。即由in引入函数
例子
//一般形式
let calAdd:(Int,Int)->(Int) = {
(a:Int,b:Int) -> Int in
return a + b
}
print(calAdd(,)) //Swift可以根据闭包上下文推断参数和返回值的类型,所以上面的例子可以简化如下
let calAdd2:(Int,Int)->(Int) = {
a,b in //也可以写成(a,b) in
return a + b
}
print(calAdd2(,))
//上面省略了返回箭头和参数及返回值类型,以及参数周围的括号。当然你也可以加括号,为了好看点,看的清楚点。(a,b) //单行表达式闭包可以隐式返回,如下,省略return
let calAdd3:(Int,Int)->(Int) = {(a,b) in a + b}
print(calAdd3(,)) //如果闭包没有参数,可以直接省略“in”
let calAdd4:()->Int = {return + }
print("....\(calAdd4())") //这个写法,我随便写的。打印出“我是250”
//这个是既没有参数也没返回值,所以把return和in都省略了
let calAdd5:()->Void = {print("我是250")}
calAdd5()
归纳:
闭包类型是由参数类型和返回值类型决定,和函数是一样的。比如上面前三种写法的闭包的闭包类型就是(Int,Int)->(Int),后面的类型分别是()->Int和()->Void。分析下上面的代码:let calAdd:(add类型)。这里的add类型就是闭包类型 (Int,Int)->(Int)。意思就是声明一个calAdd常量,其类型是个闭包类型。
"="右边是一个代码块,即闭包的具体实现,相当于给左边的add常量赋值。兄弟们,是不是感觉很熟悉了,有点像OC中的block代码块。
起别名
也可以关键字“typealias”先声明一个闭包数据类型。类似于OC中的typedef起别名
typealias AddBlock = (Int, Int) -> (Int)
let Add:AddBlock = {
(c,d) in
return c + d
}
let Result = Add(,)
print("Result = \(Result)")
尾随闭包
若将闭包作为函数最后一个参数,可以省略参数标签,然后将闭包表达式写在函数调用括号后面
func testFunction(testBlock: ()->Void){
//这里需要传进来的闭包类型是无参数和无返回值的
testBlock()
}
//正常写法
testFunction(testBlock: {
print("正常写法")
})
//尾随闭包写法
testFunction(){
print("尾随闭包写法")
}
//也可以把括号去掉,也是尾随闭包写法。推荐写法
testFunction {
print("去掉括号的尾随闭包写法")
}
值捕获
闭包可以在其被定义的上下文中捕获常量或变量。Swift中,可以捕获值的闭包的最简单形式是嵌套函数,也就是定义在其他函数的函数体内的函数。
func captureValue(sums amount:Int) -> ()->Int{
var total =
func incrementer()->Int{
total += amount
return total
}
return incrementer
}
print(captureValue(sums: )())
print(captureValue(sums: )())
print(captureValue(sums: )())
//打印"10 10 10"
这里没有值捕获的原因是,没有去用一个常量或变量去引用函数,所以每次使用的函数都是新的。有点类似于OC中的匿名对象。
let referenceFunc = captureValue(sums: )
print(referenceFunc())
print(referenceFunc())
print(referenceFunc())
//打印"10 20 30"
这里值捕获了,是因为函数被引用了,所以没有立即释放掉。所以函数体内的值可以被捕获
闭包形式
func captureValue2(sums amount:Int) -> ()->Int{
var total =
let AddBlock:()->Int = {
total += amount
return total
}
return AddBlock
}
let testBlock = captureValue2(sums: )
print(testBlock())
print(testBlock())
print(testBlock())
//打印"100 200 300"
由上面的例子都可以证得,函数和闭包都是引用类型。
当一个闭包作为参数传到一个函数中,需要这个闭包在函数返回之后才被执行,我们就称该闭包从函数中逃逸。一般如果闭包在函数体内涉及到异步操作,但函数却是很快就会执行完毕并返回的,闭包必须要逃逸掉,以便异步操作的回调。
逃逸闭包一般用于异步函数的回调,比如网络请求成功的回调和失败的回调。语法:在函数的闭包行参前加关键字“@escaping”。
//例1
func doSomething(some: @escaping () -> Void){
//延时操作,注意这里的单位是秒
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + ) {
//1秒后操作
some()
}
print("函数体")
}
doSomething {
print("逃逸闭包")
} //例2
var comletionHandle: ()->String = {"约吗?"} func doSomething2(some: @escaping ()->String){
comletionHandle = some
}
doSomething2 {
return "叔叔,我们不约"
}
print(comletionHandle()) //将一个闭包标记为@escaping意味着你必须在闭包中显式的引用self。
//其实@escaping和self都是在提醒你,这是一个逃逸闭包,
//别误操作导致了循环引用!而非逃逸包可以隐式引用self。 //例子如下
var completionHandlers: [() -> Void] = []
//逃逸
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
//非逃逸
func someFunctionWithNonescapingClosure(closure: () -> Void) {
closure()
} class SomeClass {
var x =
func doSomething() {
someFunctionWithEscapingClosure { self.x = }
someFunctionWithNonescapingClosure { x = }
}
}
自动闭包
顾名思义,自动闭包是一种自动创建的闭包,封装一堆表达式在自动闭包中,然后将自动闭包作为参数传给函数。而自动闭包是不接受任何参数的,但可以返回自动闭包中表达式产生的值。
自动闭包让你能够延迟求值,直到调用这个闭包,闭包代码块才会被执行。说白了,就是语法简洁了,有点懒加载的意思。
var array = ["I","have","a","apple"]
print(array.count)//打印出"4"
let removeBlock = {array.remove(at: )}//需要调用才会执行remove操作
print(array.count)//打印出"4"
print("执行代码块移除\(removeBlock())")
//打印出"执行代码块移除apple" 这里自动闭包返回了apple值
print(array.count)
//打印出"3"
学习swift从青铜到王者之swift闭包06的更多相关文章
- 学习swift从青铜到王者之swift属性09
1.结构体常量和类常量的存储属性 let p1 = Person1() //p1.age = 88 不允许修改 //p11.name = "yhx1" 不允许修改 var p11 ...
- 学习swift从青铜到王者之swift结构体和类08
定义 // 定义类 class StudentC{ } // 定义结构体 struct StudentS{ } 定义存储属性 // 定义类 class StudentC{ var name:Strin ...
- 学习swift从青铜到王者之swift枚举07
空枚举 //空枚举 enum SomeEnumeration { // enumeration definition goes here } 枚举基本类型 //枚举基本类型 enum CompassP ...
- 学习swift从青铜到王者之Swift语言函数05
1.定义一个函数以及调用 //一,定义一个无参无返回值函数 func fun1(){ print("this is first function") } fun1() 2.定义一个 ...
- 学习swift从青铜到王者之Swift控制语句04
1 if语句基本用法 if boolean_expression { /* 如果布尔表达式为真将执行的语句 */ } 如果布尔表达式为 true,则 if 语句内的代码块将被执行.如果布尔表达式为 f ...
- 学习swift从青铜到王者之Swift集合数据类型03
1 数组的定义 var array1 = [,,,] var array2: Array = [,,,] var array3: Array<Int> = [,,,] var array4 ...
- 学习swift从青铜到王者之swift基础部分01
1.1 变量和常量 var 变量名称 = 值(var可以修改) let 常量名称 = 值(let不可以修改) 1.2 基本数据类型 整数类型和小数类型 两种基本数据类型不可以进行隐式转换 var in ...
- 学习swift从青铜到王者之字符串和运算符02
1 字符和字符串初步 var c :Character = "a" 2 构造字符串 let str1 = "hello" let str2 = " ...
- 学习Android从青铜到王者之第一天
1.Android四层架构 一.Linux Kernel 二.Libraries和Android Runtime 三.Application Framework 四.Applications 一.Li ...
随机推荐
- Python3基础教程(十九)—— 项目结构
本节阐述了一个完整的 Python 项目结构,你可以使用什么样的目录布局以及怎样发布软件到网络上. 创建Python项目 我们的实验项目名为 factorial,放到 /home/shiyanlou/ ...
- uva1442 Cav
连通器向左向右扫描两次即可每一段有水的连通区域,高度必须相同,且不超过最低天花板高度if(p[i] > level) level = p[i]; 被隔断,要上升(隔断后,之前的就不变了,之后的从 ...
- win10x64下的redis安装与使用
先引用百度百科的一段话吧,具体可以到百科查看吧. Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API.从2010年 ...
- springmvc请求方法那些事
@RequestMapping 用法详解之地址映射 (2013-08-11 16:06:58) 转载▼ 标签: it 前段时间项目中用到了RESTful模式来开发程序,但是当用POST.PUT模式 ...
- set容器几个关键函数
set在OI中非常好用,归纳几种常见的功能qwq #include<iostream> #include<cstdio> #include<set> //set容器 ...
- MySQL数据库常见面试题
什么是存储过程?有哪些优缺点? 存储过程简单来说就是为了以后使用而保存的一条或多条预编译SQL语句,这些语句块像一个方法一样执行一些功能. 优点: 类似于封装,简化操作: 不用反复建立一系列处理步骤, ...
- centos7 中源码安装nginx
使用nginx有一段时间了,还是有很多东西不懂的,在这里做一下自己学习过程中的一些整理,能使自己得到提升. 1.环境:centos7 1511 最小化安装 2.下载nginx,可以在系统中下载,也可 ...
- Mysql when case 批量更新
UPDATE categories SET display_order = CASE id WHEN 1 THEN 3 WHEN 2 THEN 4 WHEN 3 THEN 5 END WHERE id ...
- img元素srcset属性浅析
img srcset 属性 img 元素的 srcset 属性用于浏览器根据宽.高和像素密度来加载相应的图片资源. 属性格式:图片地址 宽度描述w 像素密度描述x,多个资源之间用逗号分隔.例如: &l ...
- 队列的JS实现及广度优先搜索(BFS)的实现
队列是先进先出(FIFO)的数据结构,插入操作叫做入队,只能添加在队列的末尾:删除操作叫做出队,只能移除第一个元素.在JS中,用数组可以很简单的实现队列.JavaScript实现排序算法 functi ...