zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    安装gmsll
    常用LInux命令和操作
    yum 一键安装 jdk
    Linux目录详解,软件应该安装到哪个目录
    安装npm
    linux安装mysql (rpm + yum)
    springboot 打包jar 运行找资源文件
    rpm包安装java jar开机自启
    centos7设置服务开机自启
    linux(centos7) nginx 配置
  • 原文地址:https://www.cnblogs.com/HackHer/p/8520872.html
Copyright © 2011-2022 走看看