Swift-内存管理,循环引用

检测循环引用

在运行时点击

 

如果有内存泄漏的问题,在左侧列表会出现如下

然后点击出问题的会出现如下图,一个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()

更详细的blog请移步:https://www.raywenderlich.com/134411/arc-memory-management-swift

原文地址:https://www.cnblogs.com/HackHer/p/8520872.html