【Swift4.2】循环引用的例子讲解

最近又想回顾下swift,现在版本已经到4.2了。。。想当时15年,我写swift2.1的时候,我遇到了很多让我感到尴尬的场景。。

https://www.cnblogs.com/rayshen/p/5038937.html

这边博客现在看起来还非常搞笑,但是当时确实是这样。好在我之前说的这些问题,在后来的swift版本中,都已经给纠正过来了(感觉swift语言组也好水)……

这次要回顾的是循环引用,这个是老生常谈的问题。在block和delegate中,如果两个对象A和B,A强引用B,B又强引用A时,A的引用计数就会变成2,这样就会造成A无法自动释放。

看一段示例代码:

class Example{
    
    private var name = "123";
    
    
    /// 正确用法1
    lazy private var rightClosure1:()->() = { [unowned self] in
        print("name is \(self.name)")
    }
    
    /// 正确用法2
    lazy private var rightClosure2:()->() = { [weak self] in
        print("name is \(self?.name ?? "")")
    }
    
    /// 函数用法不存在该问题
    private func commonFunction(){
        print("name is \(self.name)")
    }
    
    /// 错误用法
    lazy private var errorCycleClosure:()->() = {
        print("name is \(self.name)")
    }

    
    func startRight1() {
        rightClosure1()
    }
    
    func startRight2() {
        rightClosure2()
    }
    
    func startRight3() {
        commonFunction()
    }
    
    func startError() {
        errorCycleClosure()
    }
    
    deinit{
        print("Example deinit")
    }
    
}

var example:Example? = Example()
//调用正确例子1,example=nil后能正常销毁
//example?.startRight1();
//调用正确例子2,example=nil后能正常销毁
//example?.startRight2();
//调用正确例子3,example=nil后能正常销毁(函数不存在循环引用问题)
//example?.startRight3();
//调用错误例子,example=nil后没有调用deinit,说明有残留成员变量
example?.startError();
example=nil;

这里面有几个swift的知识点:

1.lazy的用法:所谓的lazy就是懒加载,在没有被getter访问时,他不进行初始化。在这里,一个闭包初始化中访问到self,因为self在此时还没生成所以需要添加lazy修饰,使他们在被访问到时才初始化。

2.[unowned self]和[weak self]和区别: [unowned self]调用closure的时候如果对象已经被释放的话,会出现crash。

3.为什么函数没影响:因为函数在内存中只分配函数地址,不是一个对象。而闭包是一个对象,是个引用类型,会被实例对象所引用,如果闭包再引用实例对象本身,就会出现循环引用。

猜你喜欢

转载自www.cnblogs.com/rayshen/p/10148499.html