检测循环引用
在运行时点击
如果有内存泄漏的问题,在左侧列表会出现如下
然后点击出问题的会出现如下图,一个Contact类的对象和一个Number类的对象循环引用
Swift 对象的生命周期
allocation: 分配内存
initialization: 初始化
使用
deinitialization:
deallocation: 回收内存
可以在init函数和deinit函数里 print,init函数在分配完内存之后调用,deinit在回收内存之前调用。
对象的有效范围(未被回收内存)
循环引用的原因
解决循环引用的方法
方案一: weak reference
关键字:weak
optional types,一定是变量var,不是let。 因为当引用计数变为0时会自动赋值为nil。
当引用计数变为0时,会调用class的deinit。
引用某个对象时不会增加对象的强引用计数。
方案二:unowned reference
关键字:unowned
应用场景: objectA 拥有 objectB, objectB 需要声明被objectA拥有,但是不能在class 里直接声明 let owner: ClassA(等价于 objectB 拥有owner这个属性,导致强引用), 所以加关键字 unowned
不会导致强引用计数增加。
unowned只能使用在reference types (例如:class), 不能使用在value types (例如:struct,array)。
对比图:
方案三:Capture list - 解决闭包引用循环
例子:
var x = 5 var y = 5 let someClosure = { // a copy of x is made at the point the closure is defined // x is captured by value // but, y is captured by reference // when the closure runs, y will be whatever it is at the point, rather than at the point of capture [x] in print("(x), (y)") } x = 6 y = 6 someClosure() // output: 5,6
执行someClosure时capture list 捕获了此时x的值,之后x的值改变并不会影响someClosure,因为someClosure使用的是x的值,但是使用的是y的引用,所以在调用someClosure()时,y的指针指向的值是6而不是5。
问题一:
在一个类中声明一个改类的闭包属性,此闭包内有调用了改类的其他属性就导致了改类的循环引用。举例:
///------------ error ------------/// class Greeting { let who: String init(who: String) { self.who = who } lazy var greetingMaker: () -> String = { return "Hello (self.who)." } }
如果这样去解决问题
// mermaid的作用域只在do{}里 // 在do{}之后调用mermaid.greetingMaker 会触发runtime exception // self.who是合法的,但是mermaid在do{}之外时已经被回收内存了 class Greeting { let who: String init(who: String) { self.who = who } lazy var greetingMaker: () -> String = { [unowned self] in return "Hello (self.who)." } } let greetingMaker: () -> String do { let mermaid = WWDCGreeting(who: "Shell") greetingMaker = mermaid.greetingMaker } greetingMaker()
会出现runtime exception
更好的解决方案:
///------------ fix error ------------/// class Greeting { let who: String init(who: String) { self.who = who } lazy var greetingMaker: () -> String = { // [unowned self] in // unowned 是非可选类型,不能再被赋值是nil,所以会出现runtime exception [weak self] in // 判断当前的self是不是nil guard let strongSelf = self else { return "Invalid" } return "Hello (strongSelf.who)." } } let greetingMaker: () -> String do { let mermaid = Greeting(who: "Shell") greetingMaker = mermaid.greetingMaker } greetingMaker()