Swift基础Swift

Swift进阶09:逃逸闭包 & 自动闭包

2021-03-04  本文已影响0人  黑白森林无间道

逃逸闭包 & 非逃逸闭包

逃逸闭包定义

闭包作为一个实际参数传递给一个函数时,并且是在函数返回之后调用,我们就说这个闭包逃逸了。当声明一个接受闭包作为形式参数的函数时,可以在形式参数前写@escaping明确闭包是允许逃逸的

image
image

非逃逸闭包的特点:

逃逸闭包的两种调用情况

1、作为属性

闭包作为存储属性时,主要有以下几点说明:

如下所示,当前的complitionHandler作为HTTeacher的属性,是在方法makeIncrementer调用完成后才会调用,这时,闭包的生命周期要比当前方法的生命周期长

//*********1、闭包作为属性
class HTTeacher {
    //定义一个闭包属性
    var complitionHandler: ((Int)->Void)?
    //函数参数使用@escaping修饰,表示允许函数返回之后调用
    func makeIncrementer(amount: Int, handler: @escaping (Int)->Void){
        var runningTotal = 0
        runningTotal += amount
        //赋值给属性
        complitionHandler = handler
    }

    func doSomething(){
        self.makeIncrementer(amount: 10) {
            print($0)
        }
    }

    deinit {
        print("HTTeacher deinit")
    }
}
//使用
var t = HTTeacher()
t.doSomething()
t.complitionHandler?(20)

//<!--打印结果-->
//20

2、延迟调用

class HTTeacher {
    //定义一个闭包属性
    var complitionHandler: ((Int)->Void)?
    
    let serialQueue = DispatchQueue(label: "networkRequests")

    
    //函数参数使用@escaping修饰,表示允许函数返回之后调用
    func makeIncrementer(amount: Int, handler: @escaping (Int)->Void){
        var runningTotal = 0
        runningTotal += amount
        //赋值给属性
        self.complitionHandler = handler
        
        //延迟调用
        DispatchQueue.global().asyncAfter(deadline: .now()+0.1) {
            print("逃逸闭包延迟执行")
            handler(runningTotal)
        }
        print("函数执行完了")
    }

    func doSomething(){
        self.makeIncrementer(amount: 10) {
            print($0)
        }
    }

    deinit {
        print("HTTeacher deinit")
    }
}

//使用
var t = HTTeacher()
t.doSomething()

//---打印结果
函数执行完了
HTTeacher deinit
逃逸闭包延迟执行
10

当前方法执行的过程中不会等待闭包执行完成后再执行,而是直接返回,所以当前闭包的生命周期要比方法长

逃逸闭包 vs 非逃逸闭包 区别

自动闭包

有下面一个例子,当conditiontrue时,会打印错误信息,即如果是false,当前条件不会执行

//1、condition为false时,当前条件不会执行
func debugOutPrint(_ condition: Bool, _ message: String){
    if condition {
        print("debug: \(message)")
    }
}
debugOutPrint(true, "Application Error Occured")
func debugOutPrint(_ condition: Bool, _ message: String){
    if condition {
        print("debug: \(message)")
    }
}

func doSomething() -> String{
    print("doSomething")
    return "Network Error Occured"
}

//---如果传入true
debugOutPrint(true, doSomething())
//----打印结果
//doSomething
//debug: Network Error Occured

//---如果传入false
debugOutPrint(false, doSomething())
//---打印结果
//doSomething

通过结果发现,无论是传入true还是false,当前的方法都会执行,如果这个方法是一个非常耗时的操作,这里就会造成一定的资源浪费。所以为了避免这种情况,需要将当前参数修改为一个闭包

//3、为了避免资源浪费,将当前参数修改成一个闭包
func debugOutPrint(_ condition: Bool, _ message: () -> String){
    if condition {
        print("debug: \(message())")
    }
}
func doSomething() -> String{
    print("doSomething")
    return "Network Error Occured"
}
debugOutPrint(false, doSomething)

修改后,当传入为false时,doSomething函数不会执行

可以通过@autoclosure将当前的闭包声明成一个自动闭包不接收任何参数,返回值是当前内部表达式的值。所以当传入一个String时,其实就是将String放入一个闭包表达式中,在调用的时候返回

//4、将当前参数修改成一个闭包,并使用@autoclosure声明成一个自动闭包
func debugOutPrint(_ condition: Bool, _ message: @autoclosure () -> String){
    if condition {
        print("debug: \(message())")
    }
}
func doSomething() -> String{
    print("doSomething")
    return "Network Error Occured"
}
//---使用1:传入函数
debugOutPrint(true, doSomething())

//---使用2:传入字符串
debugOutPrint(true, "Application Error Occured")
image

自动闭包就相当于

debugOutPrint(true, "Application Error Occured")

相当于用{}包裹传入的对象,然后返回{}内的值
{
    //表达式里的值
    return "Network Error Occured"
}

总结

上一篇 下一篇

猜你喜欢

热点阅读