//: Playground - noun: a place where people can play
import UIKit
/*
闭包
闭包(Closures)是自包含的功能代码块,可以在代码中使用或者用来作为参数传值。
闭包相当于oc中的block,语法格式不一样,但作用是一样的
主要是用于两个类之间的异步回调
闭包可看作是int、float一样是一种数据类型,一种可以作为参数传递的数据类型
格式:
{
(参数)-> 返回值类型 in
执行语句
}
*/
//(1)一般形式
letcalAdd:(Int,Int)->(Int) = {
(a:Int,b:Int)->Intin
returna + b
}
calAdd(100,200)
//(2)简化形式
//swift可以根据闭包上下文推断参数和返回值的类型,所以上面的例子可以简化如下
letcalAdd2:(Int,Int)->(Int) = {
a,bin // 也可以写成(a,b) in
returna + b
}
calAdd2(10,20)//省略了返回箭头和返回值类型,以及参数周围的括号
//(3)单行表达式闭包可以隐式返回,如下,省略return
letcalAdd3:(Int,Int)->(Int) = {(a,b)ina + b }
calAdd3(20,30)
//(4)如果闭包没有参数,可以直接省略“in”
letcalAdd4:()->Int= {return1+2}
print("\(calAdd4())")
//(5)最简单闭包 这个是既没有参数也没有返回值,所以return和in都省略了
letcalAdd5:()->Void= {
print("既没有参数也没有返回值,所以return和in都省略了")
}
//(6)闭包内嵌函数 函数表达式作为回调函数
letsumMethod:(_a:Int,_b:Int)->(Int) = {
(a,b) -> (Int)in
varb = b
funcchangeValue() -> (Int) {
b += a
returnb
}
return changeValue()
}
sumMethod(3, 4)
//补充----------------神奇的下划线
//1.格式化数字字面量
//通过使用下划线能够提高数字字面量的可读性,比如:
letpaddedDouble =123.000_001
letoneMillion =1_000_000
//2.忽略元组的元素值
//当我们使用元组时,假设有的元素不须要使用。这时能够使用下划线将对应的元素进行忽略,比如:
lethttp404Error = (404,"Not Found")
let(_, errorMessage) =http404Error
//3.忽略区间值
letbase =3
letpower =10
varanswer =1
for _ in 1...power {//只是为了算多次,不关心区间每一项的值
answer *= base
// print(answer)
}
//4.忽略外部參数名
//(1).忽略方法的默认外部參数名
//在用法(类方法或者实例方法)时,方法的第二个參数名及兴许的參数名,默认既是内部參数名,又是外部參数名。假设不想提供外部參数名,能够在參数名前加入下划线来忽略外部參数名。
varcount:Int=0
funcincrementBy(amount:Int, numberOfTimes:Int){
count+= amount * numberOfTimes
}
//在上面的代码中,方法incrementBy()中的numberOfTimes具有默认的外部參数名:numberOfTimes,假设不想使用外部參数名能够使用下划线进行忽略,代码能够写为(只是为了提高代码的可读性,一般不进行忽略):
varcount2:Int=0
funcincrementBy(amount:Int,_numberOfTimes:Int) {
count2+= amount * numberOfTimes
}
//(2).忽略具有默认值的參数的外部參数名
//当函数(或者方法)的參数具有默认值时,Swift自己主动为该參数提供与參数名一致的默认外部參数名,因此在进行函数调用的时候,要提供默认參数名。能够使用下划线进行忽略默认外部參数名(可是不推荐忽略外部參数名。这主要是为了调用的时候能够方便地知道每一个參数的含义)
funcjoin(s1:String, s2:String, joiner:String=" ") ->String{
returns1 + joiner + s2
}
join(s1:"hello", s2:"swift", joiner:"-")
//假设不想使用默认外部參数名,能够进行例如以下改动:
funcjoin2(s1:String, s2:String,_joiner:String=" ") ->String{
returns1 + joiner + s2
}
join2(s1: "hello", s2: "world", "-")
join2(s1: "good", s2: "morning")
//(7)闭包内嵌闭包
letstrFormat:(_str1:String,_str2:String,_x:Int) ->Int= {
(str1,str2,x)in
letcalcute:(Int)->Int= {
return$0
}
returncalcute(x)
}
strFormat("a", "b", 5)
//归纳:闭包类型是由参数和返回值决定,和函数一样
//(8)起别名 关键字 typealias声明一个闭包数据类型,类似于OC中的typedef别名
typealiasAddBlock = (Int,Int)->(Int)
letadd:AddBlock= {
(a,b)in
returna+b
}
add(5,5)
//(9)尾随闭包 若将闭包作为最后一个参数,可以省略参数标签,然后将闭包表达式写在函数调用括号后面
functestFunction(testBlock:()->Void){
testBlock()
}
testFunction(testBlock: {
print("正常写法")
})
testFunction(){
print("尾随闭包写法")
}
testFunction {
print("去掉括号的尾随闭包写法")
}
//值捕获
//闭包可以定义在其被定义的上下文中捕获常量或者变量,swift中可以捕获值的形式比如嵌套函数,也就是定义在其他函数的函数体内
//逃逸闭包
//当一个闭包作为参数传到一个函数中,需要这个闭包在函数返回之后才被执行,我们就称该闭包从函数中逃逸,一般如果闭包在函数体内涉及到异步操作,但函数却是很快就会执行完毕并返回的,闭包必须要逃逸掉,以便异步操作的回调
//逃逸闭包一般用于一部分回调函数的回调,比如网络请求成功的回调和失败的回调,语法仔函数的闭包行前加关键字@escaping
//示例1
funcrequestData(urlStrings :String,parameter : [String:Any],successData :@escaping(Any?)->(Void),failData :@escaping(Any?)->(Void)) {
successData("请求成功")
failData("请求失败")
print("函数体")
}
//示例2
varcomletionHandle:()->String= {"喜欢看电影吗?"}
funcdoSomething(some:@escaping()->String){
comletionHandle = some
}
doSomething{
return "喜欢"
}
print(comletionHandle())
//自动闭包
//顾名思义,自动闭包是一种自动创建的闭包,封装一堆表达式在自动闭包中,然后将自动闭包作为参数传给函数。而自动闭包是不接受任何参数的,但可以返回自动闭包中表达式产生的值。
//自动闭包让你能够延迟求值,直到调用这个闭包,闭包代码块才会被执行
var array = ["I","have","a","apple"]
print(array.count)
letremoveBlock = {
array.remove(at:3)
}
print(array.count)
print("执行代码块移除\(removeBlock())")
//打印出"执行代码块移除apple" 这里自动闭包返回了apple值
print(array.count)
//闭包捕获值
funcgetIncFunc(inc:Int) -> (Int) ->Int
{
varmax =10
funcincFunc(x :Int) ->Int{
print("incFunc函数结束")
returninc + x
// max += 1
// return max + x
}
// 当执行到这一句时inc参数就应该被释放了, 但是由于在内部函数中使用到了它, 所以它被捕获了
// 同理, 当执行完这一句时max变量就被释放了,但是由于在内部函数中使用到了它, 所以它被捕获了
print("getIncFunc函数结束")
return incFunc
}
// 被捕获的值会和与之对应的方法绑定在一起, 同一个方法中的变量会被绑定到不同的方法中
print("-------------")
letincFunc =getIncFunc(inc:5)
print(incFunc(2))
print(incFunc(5))
letincFunc2 =getIncFunc(inc:5)
print(incFunc2(5))
print("-------------")
//练习page707
//1、哪个句子最好描述一个闭包?3
//A最后一个函数在swift文件中。
//B可以全局执行的匿名函数。
//C可以作为变量存储或作为参数传递的代码块。
//D可以在范围内执行的指定代码块。
//4、以下哪一个不是一个接受闭包作为参数的函数?4
//5、5
//A map()返回与原始数组相同长度的新数组。
//B map()是一个对象的集合映射到其他对象的集合
//C、map()对数组中的每个对象执行一个闭包。
funcsumd(numberss:[Int]) ->Int{
return 5
}
sumd(numberss: [2])
sumd(numberss: [11])