- 闭包表达式默认会对用到的外层对象产生额外的强引用(对外层对象进行了retain操作)
class Dog {
var fn: (() -> ())?
func run() {
print("run")
}
deinit {
print("deinit")
}
}
func test() {
let d = Dog()
d.fn = {
d.run()
}
}
test()
此时dog对象指向了闭包,而闭包也指向了dog对象,造成循环引用,导致dog对象无法释放(deinit不会调用)
- 在闭包表达式的捕获列表声明
weak或unowned引用,解决循环引用
// 捕获列表 [], [weak p], 无参数列表
d.fn = {
[weak p] in
d?.run()
}
class Dog {
var fn: ((Int) -> ())?
func run() {
print("run")
}
deinit {
print("deinit")
}
}
func test() {
let d = Dog()
d.fn = {
d.run()
}
}
test()
// 捕获列表 [], [weak p], 有参数列表
d.fn = {
// 也可 [weak weakSelf = p]
[weak p](age) in
d?.run()
}
- @escaping 一般是作为参数传递给函数
// 非逃逸闭包:闭包调用发生在函数结束前, 闭包调用在函数作用域内
func test(_ fn: () -> ()) {
fn()
}
test {
print("test")
}
// 逃逸闭包:闭包有可能在函数结束后调用, 闭包调用逃离了函数作用域,此时需要@escaping声明
import Dispatch
typealias Fn = () -> ()
class Person {
var fn: Fn?
init(fn: @escaping Fn) {
self.fn = fn
}
func test() {
// DispatchQueue.global().async也是一个逃逸闭包
// 因为用到了实例成员(属性、方法),编译器会强制要求明确写出self, 此处没有循环引用
DispatchQueue.global().async {
[weak weakSelf = self] in
weakSelf?.fn()
}
// 也可
DispatchQueue.global().async {
self.fn()
}
}
}