Search code examples
iosswiftmemory-managementweak-referencesdealloc

Strong references and UIView memory issues


I'm dealing with some deallocation issue and perhaps strong or circular referencing that can't figure out. I have three UIViews instantiating like below:

There is one main ViewController which I have added a UIView inside it in storyboard and the UIView has a weak outlet inside the class like:

class ViewController : UIViewController {

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

} 

second UIView is added as a subview to the first view programmatically like:

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()
        }
       }

} 

Now the SecondViewClass is :

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)

} 

Now if user taps the button to remove mySecondView and then add it again at some other time (still in the same ViewController) I expect all the subviews of mySecondView to have been released and gone but they are all there. I would appreciate it a lot if someone can point it to me where am I keeping a strong reference or if there is a circular referencing issue? or perhaps something else?


Solution

  • You have two strong references to your views, your custom property and the view hierarchy reference established when you call addSubview. When you remove the view from the view hierarchy, your class, itself, still has its strong reference to it.

    You could solve this by making your reference optional, and when you call removeFromSuperview, also manually set your reference to nil. Or, perhaps easier, you might resolve this by using weak references, letting the view hierarchy maintain the strong references for you. And because your custom property is weak, when you remove it from the view hierarchy (thus eliminating the only strong reference to it), your weak reference will automatically become 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()
        }
    }