闭包英文名叫closure , 在swift开发项目中随处可见, 它的本质和函数差不多,但是却比函数使用方便,因为swift中可以通过上下文识别传入的值,我们就不用像使用函数一样把全部的值都定义一边!当一个函数返回值或着参数需要传入一段逻辑运算或操作,就可以考虑去使用闭包,在OC语言中我们称之为block ,在Java语言中我们称之为Lamdba,这种调用函数的方法,也叫做函数式编程
下面看一个闭包使用的例子 创建一个数组 并用.sorted函数按照用户传入的排序逻辑排序
var num : [Int] = [1,34,5,7,88,8,5]
//可以看到系统要我们传入的是 两个Int参数 并返回一个Bool值
num.sorted(by: <#T##(Int, Int) throws -> Bool#>)
//我们把这段排序逻辑写成函数形式 a>b返回true 就是说a大的话就排前面
num.sorted(by: { (a : Int,b : Int) -> Bool in a>b })
排序后结果为[88, 34, 8, 7, 5, 5, 1] ,sort函数系统默认是从小到大排序的
当然既然传入的是一个函数 系统自带的+ - * /这些都是操作函数
num.sorted(by: >)
这样得到的结果也一样 从大到小排序
下面我们看一下三个著名的函数式编程式 他们都是系统对象自带的函数
//函数式编程的著名公式
//map函数 Int -> Any
//假定数组里面的是一个班的成绩 我们把低于60分的数据转成字符串"不及格" 反则是"及格"
//把原来装着Int的数组改变成一个装着字符串的数组
//当然你也可以转成Bool 或者把Int都转成二进制
func TransformMethod1(score:Int) ->String{
return score<60 ? "不及格": "及格"
}
//传入函数
num.map(TransformMethod1)
//传入闭包
num.map({ (score)-> String in
score>60 ? "及格":"不及格"
})
//filter函数
//过滤去不要的信息 比如拿到分数里面高于80分的学生数组
func getScoreOverEighty(score:Int) ->Bool{
return score>80
}
//传入函数
num.filter(getScoreOverEighty)
//传入闭包
num.filter({a in return a>80})
//reduce函数
// 一般用于求数组中所有数的和
func reduceMethod(a : Int ,b : Int)->Int{
return a+b
}
//传入函数
num.reduce(0, reduceMethod)
//传入闭包
num.reduce(0, {a,b in a+b})
闭包的结尾式写法 当闭包作为函数最后一个参数的时候 可以把闭包放在括号外面 可以让人更加清晰的读出这个闭包的逻辑
let num : [Int] = [1,2,3,4,5,6,7]
//设置一个闭包 把所有数转化成二进制
//这里不知道要返回哪个值 所以需要声明返回值
num.map(){(number)->String in
var number = number
var result = ""
repeat{
result = String(number%2) + result
number /= 2
}while number != 0
return result
}
//返回后的数组值 ["1", "10", "11", "100", "101", "110", "111"]
//当然map函数没有改变原数组
开发IOS人员经常接触的结尾式写法 就是UIView里面的动画执行了 括号放在外面 我们就可以更专注于逻辑的实现而不是该方法的参数是什么
//执行时间3秒钟
UIView.animate(withDuration: 3.0) {
sonV.backgroundColor = UIColor.white
sonV.frame = fatherV.frame
}
闭包的更多用法-闭包作为返回值 当然都是涉及函数式编程思想
下面是函数做为返回值的写法
import UIKit
//设置两个函数 计算自助餐中剩余食物的收费计算方法
//不用额外收费
func chargeMethod1(left:Int)->Int{
return 0
}
//超出10单位的剩余食物每单位加收15的费用
func chargeMethod2(left:Int)->Int{
return (left-10)*15
}
func chargeForResidualFoodInBuffet(_ left:Int,_ orignalPrice:Int) ->Int{
//把该接口隐藏
//如果剩余食物少于10个单位 就采用第一种收费方式 否则就采用第二种
func chooseChargeMethodByResidualFood(_ left :Int) -> (Int)->Int{
return left<10 ? chargeMethod1:chargeMethod2
}
//得到计算的方法
let method = chooseChargeMethodByResidualFood(left)
//返回 剩余食物价钱+原价
return method(left)+orignalPrice
}
下面是闭包代替函数的写法 代码量更少了
import UIKit
func chargeForResidualFoodInBuffet(_ left:Int,_ orignalPrice:Int) ->Int{
//把该接口隐藏
func chooseChargeMethodByResidualFood(_ left :Int) -> (Int)->Int{
//闭包式写法
//由于少于10的时候不收取费用 所以我们不需要拿到参数 _代替
return left<10 ? { _ in return 0} : { a in return (a-10)*15 }
}
//得到计算的方法
let method = chooseChargeMethodByResidualFood(left)
return method(left)+orignalPrice
}
注意⚠️ 闭包和函数都是引用类型的 不是值类型
import UIKit
//使用函数返回值
func eat( food:Int) -> ()->Int
{
var totalCarolias = 0
func PersonalEnergy() ->Int {
totalCarolias = food + totalCarolias
return totalCarolias
}
return PersonalEnergy
}
//使用闭包返回值
func eat1( food:Int) -> ()->Int
{
var totalCarolias = 0
return {
totalCarolias = food + totalCarolias
return totalCarolias
}
}
//闭包其为引用类型 所以totalCarolias开辟了一片存储空间 随闭包的调用而改变
//peopleA 加上()表明调用函数
let peopleA = eat(food: 500)
peopleA() //500
peopleA() //1000
peopleA() //1500
let peopleB = eat1(food: 600)
peopleB() //600
peopleB() //1200
peopleB() //1800
这里eat(food : )每调用一次也会会开辟一个新的空间 这时候才会创建一个新的totalCarolias