Swift学习笔记

Swift - 内存管理

2022-04-24  本文已影响0人  aven_kang
跟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.png
typealias 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'

会报错

上一篇下一篇

猜你喜欢

热点阅读