当方法的输入参数是一个方法时,可以使用简化程序。
如数组有个sort排序的方法,传入参数是 (x: T, y: T) -> Bool 类型的方法,不用闭包,使用sort方法
func compare(x: Int, y: Int) -> Bool {
return x > y
}
var array: [Int] = [1, 3, 2, 5, 9, 3]
array.sort(by: compare)
闭包
我们来使用闭包使用sort方法
array.sort(by: { (x: Int, y: Int) -> Bool in
return x < y
})
有点类似于匿名方法,注意关键字 in
简化输入返回类型
其实swift会帮我们推断方法输入和返回的类型,所以我们可以这么写
array.sort(by: { x, y in
return x > y
})
单行表达式简化 return
因为我们 in 块内只有一行表达式 return x > y,此时我们还能省略 return 关键字
array.sort(by: { x, y in
x > y
})
简化参数 in
由于方法的参数可以用0,1这种方式表示,so我们还可以去掉参数 x,y,此时的in也没有必要了
array.sort(by: {
$0 > $1
})
其实还能更简便,我觉得吧,没必要了吧,这已经很简便了,个人认为!!
尾随闭包
var array: [Int] = [1, 3, 2, 5, 9, 3]
array.sort(by: {$0 > $1})
如果方法的最后一个输入参数是方法的话,我们可以使用尾随闭包
var array: [Int] = [1, 3, 2, 5, 9, 3]
// 尾随闭包
array.sort(){$0 > $1}
由于sort方法中,by是唯一参数,所以我们调用sort方法时,还能把()省略掉
var array: [Int] = [1, 3, 2, 5, 9, 3]
// 尾随闭包,省略()
array.sort {$0 > $1}
其实省略()之后,倒是有点看不懂了,哈哈!!
值捕获
嵌套函数是一种有名字的闭包,包围嵌套函数叫外围函数。闭包可以在其定义的上下文中捕获常量或者变量,在嵌套函数中,外围函数就是其上下文,所以嵌套函数可以捕获外面函数传入的值和定义的变量或者常量。
func incrementor(step: Int) -> () -> Int {
int count = 0;
func increment() -> Int {
count += step;
return count;
}
}
let incrementorTen = incrementor(10)
incrementorTen() // 10
incrementorTen() // 20
incrementorTen() // 30
let incrementorTwo = incrementor(2)
incrementorTwo() // 2
incrementorTwo() // 4
incrementorTen() // 40
嵌套函数 increment 没有输入,它捕获了外围函数 incrementor 的传入参数引用和 count参数的引用,所以可以一直使用,并进行累加操作。
闭包是引用类型
从上面的例子可以看出,incrementorTen没有输入参数,却能不断的累加,这是因为闭包是一种引用类型,incrementorTen持有嵌套函数的引用,才能捕获到上下文的常量或者变量。
let alsoIncrementorTen = incrementorTen
alsoIncrementorTen() // 50
逃逸闭包
如果闭包作为函数的输入,而且这个闭包在函数返回后才执行,就说这个闭包是一个逃逸闭包。简单的来说,就是我们传入的闭包没有在函数内执行。声明一个逃逸闭包的方式是在参数类型前加“@escaping”。
举个例子:
/**
* 异步执行后在UI执行的操作
**/
func doInUI(result: String) {
print("this result is \(result)")
}
/**
* 执行异步操作
**/
func doAsync(uiOperation: @escaping(String) -> Void) {
// 模仿异步执行
AsyncTask.excute { result in
uiOperation(result)
}
print("doAsync is finish")
}
doAsync(doInUI)
以例子看,doAsync方法已经执行完了,AsyncTask异步(如访问网络)还没执行完,所以uiOperation方法是在函数外执行的,因此uiOperation就是一个逃逸闭包。
从这里看,其实和java非常相似,我们来看看java的
public class UITask {
public void doInUI(String result) {
System.out.println("this result is " + result);
}
}
public class AsyncTask {
public void doAsync(final UITask task) {
// 执行网络异步操作
OkHttpClient mOkHttpClient = new OkHttpClient();
final Request request = new Request.Builder().url("https://www.baidu.com/").build();
Call call = mOkHttpClient.newCall(request);
call.enqueue(new Callback(){
@Override
public void onFailure(Request request, IOException e) {
}
@Override
public void onResponse(final Response response) throws IOException {
String result = response.body().string();
task.doInUI(result);
}
});
}
}
AsyncTask的doAsync方法传入的参数也要“final”关键字。