【问题标题】:Retain cycle between class and struct在类和结构之间保持循环
【发布时间】:2017-07-26 16:57:10
【问题描述】:

假设我有以下代码:

struct X {
    let propertyOfTypeY: Y
}

class Y {
    var propertyOfTypeX: X?
}

let y = Y()
let x = X(propertyOfTypeY: y)
y.propertyOfTypeX = x

如果这两个都是类,那么这将意味着一个保留循环。但是,我不清楚类和结构之间的差异如何应用于上面的示例。会导致retain循环,还是因为使用了struct而成为安全代码?

【问题讨论】:

    标签: swift memory-leaks retain-cycle


    【解决方案1】:

    是的,你有一个保留周期。

    y.propertyOfTypeX = x
    

    将值x 复制到y.propertyOfTypeX,包括 属性x.propertyOfTypeY 是对y 的引用。

    因此

    y.propertyOfTypeX?.propertyOfTypeY === y
    

    持有。你所拥有的与

    class Y {
        var propertyOfTypeY: Y?
    }
    
    var y = Y()
    y.propertyOfTypeY = y
    

    只有propertyOfTypeYstruct X 的一部分 (并且x 包含对y 的附加引用)。

    【讨论】:

    • 可能有用的是注意'struct X { unowned let propertyOfTypeY: Y }'将允许循环被打破。
    【解决方案2】:

    TL;DR 有一个保留周期,但您可以自己查看 自己

    struct X {
        let propertyOfTypeY: Y
    }
    
    class Y {
        var propertyOfTypeX: X?
    
        deinit {
            print("I was deinit'ed")
        }
    }
    
    do {
        let y = Y()
        let x = X(propertyOfTypeY: y)
        y.propertyOfTypeX = x
    }
    // y and x should be dealloc'ed here, because the "do scope" ends
    

    注释掉y.propertyOfTypeX = xI was deinit'ed 将被打印出来,但是如果你这样做,deinit 永远不会被调用。

    如果你使用闭包,也会发生同样的事情。

    【讨论】:

    • 一个类似的“技巧”是将代码放在do { ... } 块中,并在执行该块后检查是否调用了 deinit。这甚至适用于非可选项。
    【解决方案3】:

    内存图显示参考周期

    肯定有retain循环。

    解决方法:应该unownedweak打破循环

    struct X {
        unowned let propertyOfTypeY: Y
    }
    
    class Y {
        var propertyOfTypeX: X?
    
        deinit {
            print("Y deallocated")
        }
    }
    
    do {
        let y = Y()
        let x = X(propertyOfTypeY: y)
        y.propertyOfTypeX = x
    }
    

    【讨论】:

      猜你喜欢
      • 2017-09-19
      • 2021-11-26
      • 1970-01-01
      • 1970-01-01
      • 2017-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多