Swift基础 闭包

当方法的输入参数是一个方法时,可以使用简化程序。

如数组有个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”关键字。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值