强引用和 UIView 内存问题

Strong references and UIView memory issues

我正在处理一些无法解决的重新分配问题,也许是强引用或循环引用。我有三个 UIViews 实例化如下:

有一个主 ViewController,我在故事板中添加了一个 UIViewUIView 在 class 中有一个 weak 出口喜欢:

class ViewController : UIViewController {

    //MARK: - outlets
    @IBOutlet weak var firstView: FirstUiview!

} 

second UIView 作为子视图以编程方式添加到第一个视图,如:

class FirstUiview : UIView { 

        //creating an instance of secondUiView 
        lazy var mySecondView: SecondViewClass = {
          let dv = SecondViewClass()
          dv.backgroundColor = UIColor.red
          return dv
        }()


        //sometime later by clicking on a button 
        self.addSubview(mySecondView)

        //a button will be tapped to remove mySecondView; 
        //later will be called at some point upon tapping:

       func removingSecondViewByTapping()  {
         if mySecondView.isDescendant(of: self) {
           mySecondView.removeFromSuperview()
        }
       }

} 

现在 SecondViewClass 是:

class SecondViewClass : UIView { 

      //in this class I create bunch of uiview objects like below: 
      lazy var aView : UIView = {
        let hl = UIView()
        hl.tag = 0
        hl.backgroundColor = UIColor.lightGray
        return hl
      }()

      self.addSubview(aView) //... this goes on and I add other similar views the same way.

        //creating an instance of thirdView
        var let thirdView = UIView() 
        self.addSubview(thirdView)

} 

现在,如果用户点击按钮删除 mySecondView,然后在其他时间再次添加它(仍然在同一个 ViewController 中),我希望 mySecondView 的所有子视图已经被释放并消失了,但他们都在那里。如果有人能指出我在哪里保留强引用或者是否存在循环引用问题,我将不胜感激?或者别的什么?

您有两个对视图的强引用,您的自定义 属性 和调用 addSubview 时建立的视图层次结构引用。当您从视图层次结构中删除视图时,您的 class 本身仍然具有对它的强引用。

您可以通过将您的引用设置为可选来解决这个问题,并且当您调用 removeFromSuperview 时,也可以手动将您的引用设置为 nil。或者,也许更简单,您可以通过使用 weak 引用来解决此问题,让视图层次结构为您维护强引用。并且由于您的自定义 属性 是 weak,当您将其从视图层次结构中删除时(从而消除了对它的唯一强引用),您的 weak 引用将自​​动变为 nil :

class FirstView: UIView {

    weak var secondView: SecondView?       // note the `weak` reference, which is obviously an optional

    //sometime later by clicking on a button

    func doSomething() {
        let subview = SecondView()
        subview.backgroundColor = .red
        self.addSubview(subview)
        secondView = subview
    }

    // a button will be tapped to remove secondView;
    // later will be called at some point upon tapping ...

    func removingSecondViewByTapping()  {
        secondView?.removeFromSuperview()
    }
}