标签:elf private getter vat 遇到 引用计数 类型 error init
最近又想回顾下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 errorCycleClosure1:()->() = { print("name is \(self.name)") } /// 错误用法(函数赋值给errorCycleClosure2,errorCycleClosure2变成一个闭包对象被引用,函数是这个闭包的实现) lazy private var errorCycleClosure2 = commonFunction; func startRight1() { rightClosure1() } func startRight2() { rightClosure2() } func startRight3() { commonFunction() } func startError1() { errorCycleClosure1() } //需要特殊警惕的情况,一旦函数被赋值给一个被引用的对象后,也会出现循环引用的情况 func startError2() { errorCycleClosure2() } deinit{ print("Example deinit") } } var example:Example? = Example() //调用正确例子1,example=nil后能正常销毁 //example?.startRight1(); //调用正确例子2,example=nil后能正常销毁 //example?.startRight2(); //调用正确例子3,example=nil后能正常销毁(函数不存在循环引用问题) //example?.startRight3(); //调用错误例子1,example=nil后没有调用deinit,说明有残留成员变量 //example?.startError1(); //调用错误例子2,example=nil后没有调用deinit,说明有残留成员变量 example?.startError2(); example=nil;
这里面有几个swift的知识点:
1.lazy的用法:所谓的lazy就是懒加载,在没有被getter访问时,他不进行初始化。在这里,一个闭包初始化中访问到self,因为self在此时还没生成所以需要添加lazy修饰,使他们在被访问到时才初始化。
2.[unowned self]和[weak self]和区别: [unowned self]调用closure的时候如果对象已经被释放的话,会出现crash。
3.为什么函数直接调用没影响:因为函数在内存中只分配函数地址,不是一个对象。而闭包是一个对象,是个引用类型,会被实例对象所引用,如果闭包再引用实例对象本身,就会出现循环引用。
标签:elf private getter vat 遇到 引用计数 类型 error init
原文地址:https://www.cnblogs.com/rayshen/p/10148499.html