TheeBen TheeBen - 1 month ago 7
iOS Question

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

UIView
s 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?

Rob Rob
Answer

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