跟OC一样,Swift也是采用基于引用计数的ARC内存管理方案(针对堆空间)
Swfit的ARC中有三种引用
1.强引用 Strong
2.弱引用 Weak
弱引用必须是可选类型的var,因为实例销毁后,ARC会自动将弱引用设置为nil
ARC自动给弱引用设置为nil时,不会触发属性观察器
3.无主引用(unowned reference): 通过unowned定义无主引用
不会产生强引用,实例销毁后仍然存储着实例的内存地址(类似OC中的unsafe_unretained)
试图在实例销毁后访问无助引用,会产生运行时错误(野指针)
weak、unowned的使用限制
只能使用在类实例上面
protocol Liveable : AnyObject {}
class Person {}
weak var p0: Person?
weak var p1:AnyObject?
weak var p2 : Liveable?
unowned var p10: Person?
unowned var p11:AnyObject?
unowned var p12 : Liveable?
循环引用
weak、unowned都能解决循环引用,unowned要比weak少一些性能消耗
在生命周期中可能变成nil的使用weak
初始化赋值后再也不会变为nil的使用unowned
截屏2022-03-03 下午4.12.27.png
闭包的循环引用
class blockTest {
var fn: (() -> ())?
func run(){
print("test")
}
deinit {
print("deinit")
}
}
上述代码中,我们定义了一个类,带有一个block,我们在调用的时候
var b = blockTest()
b.fn = {
b.run()
}
会发现blockTest这个类的deinit这个方法并为执行,说明发生了循环引用
这需要我们在闭包里面加上这句
var b = blockTest()
b.fn = {
[weak b] in
b?.run()
}
// [weak b] 把捕获的这个b置为弱引用
截屏2022-03-03 下午4.26.16.png
如果想在定义闭包属性的同时引用self,这个闭包必须是lazy,因为在实例初始化完毕之后才能引用self
class test2 {
lazy var fn:(()->()) = {
[weak self]
self.run()
}
func run() {
print("run")
}
deinit {
print("test2 deinit")
}
}
逃逸闭包与非逃逸闭包
截屏2022-03-03 下午5.32.31.pngtypealias Fn = ()->()
class Person {
var fn:Fn
init(fn:@escaping Fn){
self.fn = fn
}
func run(){
DispatchQueue.global().async {
self.fn()
}
}
deinit {
print("hah deinit")
}
}
let person = Person(fn: {
print("我终于要执行了")
})
person.run()
这个就是典型的逃逸闭包,闭包在赋值后并未直接调用,有位可能在未来的某个时刻调用
逃逸闭包不可以捕获inout参数
func other1(_ fn:Fn) {
fn()
}
func other2(_ fn: @escaping Fn) {
fn()
}
func test(value: inout Int) -> Fn {
other1 {
value += 1
}
other2 {
value += 1
}
func plus(){
value += 1
}
return plus
}
如下图
截屏2022-03-04 下午4.13.46.png
Escaping closure captures 'inout' parameter 'value'
会报错
网友评论