Swift 闭包

2021-01-12  本文已影响0人  H丶ym

什么是闭包

闭包是一个捕获了上下文常量或者变量的函数

闭包表达式

OC中的block类似,这个表达式需要具备

var closure : (Int) -> Int = { (age: Int) in
    return age
}

这个闭包的参数为Int,返回值为Int
我们可以将这个闭包声明成一个可选类型

var clourse:((Int)->(Int))?

同时也可以作为函数的参数

func test(param:(Int)->(Int)){
    let a = param(10)
    print(a)
}

test { (param) -> (Int) in
    return param+1
}
尾随闭包

一种书写方式,用来提高代码可读性,当闭包表达式作为函数的最后一个参数时,将当前闭包表达式的{}放在函数外面,一般编译器会帮我们做

func test(_ a: Int, _ b: Int, _ c: Int, by: (_ item1: Int, _ item2: Int, _ item3: Int) -> Bool) -> Bool{
   return  by(a, b, c)
}

test(10, 20, 30){(_ item1: Int, _ item2: Int, _ item3: Int) -> Bool in
   return (item1 + item2 < item3)
}
闭包强大的推算能力
var array = [1, 2, 3]

array.sort{(item1 : Int, item2: Int) -> Bool in return item1 < item2 }

//省略参数类型  由array的类型推算
array.sort(by: {(item1, item2) -> Bool in return item1 < item2 })

//省略闭包返回值,由 in 后面的函数体推算
array.sort(by: {(item1, item2) in return item1 < item2 })

//尾随闭包写法
array.sort{(item1, item2) in item1 < item2 }

//省略参数声明,由闭包内嵌参数代替
array.sort{ return $0 < $1 }

//省略 return 关键字
array.sort{ $0 < $1 }

//省略 参数
array.sort(by: <)

捕获值

这里借助官方文档中的列子

func makeIncrementer() -> () -> Int {
    var runningTotal = 10
    func incrementer() -> Int {
        runningTotal += 1
        return runningTotal
    }
    return incrementer
}

let makeInc = makeIncrementer()
print(makeInc())
print(makeInc())
print(makeInc())
11
12
13
Program ended with exit code: 0

runningTotal是一个临时变量,每次进来的时候讲道理应该是10,但是这里的输出是一直累加的,原因是底层调用了swift_allocObject,在堆上分配了一个空间,在内嵌函数使用调用完成后释放

总结

捕获值的方式
var age = 10
let closure = {
   age += 1
}
closure()
print(age)
11
Program ended with exit code: 0
var age = 10
let closure = { [age] in
   print("闭包内:\(age)")
}
age = 11
closure()
print("闭包外:\(age)")
闭包内:10
闭包外:11
Program ended with exit code: 0

总结
自动捕获的参数可以修改,并且影响外部变量
手动捕获的参数本质是值类型,不可修改,跟外部变量没关系了

逃逸闭包

逃逸闭包的定义:当闭包作为一个实际参数传递给一个函数的时候,并且是在函数返回之后调用,我们就说这个闭包逃逸了,在闭包参数前些@escaping来明确闭包是允许逃逸的。
Swift 3.0之后,系统默认闭包参数是@nonescaping

逃逸闭包一般有两种实现

先存储,在后面进行调用举例:

class LGTeacher{

    var complitionHandler: ((Int)->Void)?

    func makeIncrementer(amount: Int,  handler: @escaping (Int) -> Void){
        var runningTotal = 10
        runningTotal += amount
        self.complitionHandler = handler
    }

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

    deinit {
        print("LGTeaher deinit")
    }

}

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()

        let t = LGTeacher()

        t.doSomething()

        t.complitionHandler?(10)
    }

}
10
LGTeaher deinit

延迟调用举例:

class LGTeacher{

    var complitionHandler: ((Int)->Void)?

    func makeIncrementer(amount: Int,  handler: @escaping (Int) -> Void){
        var runningTotal = 10
        runningTotal += amount
//        self.complitionHandler = handler
        DispatchQueue.global().asyncAfter(wallDeadline: .now() + 0.1) {
            handler(runningTotal)
        }

    }

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

    deinit {
        print("LGTeaher deinit")
    }

}

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()

        let t = LGTeacher()

        t.doSomething()

        t.complitionHandler?(10)
    }

}
10
LGTeaher deinit

逃逸闭包循环引用

非逃逸闭包是不会产生循环引用的,上下文保存栈上,而不是堆上

class LGStudent{
    var age:Int = 18
}

class LGTeacher{
    
    var student = LGStudent()
    

    var complitionHandler: (()->Void)?

    func makeIncrementer(handler: @escaping () -> Void){
        self.complitionHandler = handler
    }

    func doSomething(){
        self.makeIncrementer{
            print(self.student.age)
        }
    }

    deinit {
        print("LGTeaher deinit")
    }

}

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()

        let t = LGTeacher()

        t.doSomething()

        t.complitionHandler?()
    }

}
18

只打印了18,没有打印LGTeaher deinit

使用[weak self] 或者 [unowned self]解决循环引用

self.makeIncrementer{ [weak self] in
    print(self?.student.age)
}
self.makeIncrementer { [weak student] in
    print(student?.age)
}
self.makeIncrementer { [unowned self] in
    print(self.student.age)
}
self.makeIncrementer { [unowned student] in
    print(student.age)
}
18
LGTeaher deinit

总结

上一篇 下一篇

猜你喜欢

热点阅读