Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIView init with coder causes a recursion

Tags:

ios

swift

uiview

I am trying to embed a UIView I've prepared, which is located in a xib file, to a storyboard.

What I've done so far is:

class TestUIView : UIView {
    @IBOutlet weak private var firstButton: UIButton!
    @IBOutlet weak private var secondButton: UIButton!

    // MARK - Lifetime

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        let view = NSBundle.mainBundle().loadNibNamed("TestUIView", owner: self, options: nil).first as! TestUIView

        self.addSubview(view)
    }
}

But for some reason I get bad access memory exception. From looking into stack trace I see a whole bunch of calls to initWithCoder http://i.stack.imgur.com/iH6Am.png I'm not sure why NSBundle.mainBundle().loadNibNamed causes this, any ideas?

like image 539
Gil Polak Avatar asked Nov 29 '15 11:11

Gil Polak


3 Answers

Turn's out what I have done wrong is how I prepared the .xib file, I've set the View itself, instead of the file owner to TestUIView class. After changing the file owner(and reseting the constraints), everything worked fine.

like image 144
Gil Polak Avatar answered Sep 30 '22 18:09

Gil Polak


For future seekers....

Brief : The recursive call of required init?(coder aDecoder: NSCoder) occurs when you accidentally set your custom view class in identity inspector of your ContentView.

When the compiler tries to load your Nib file(the owner view) it first needs to initiate your ContentView (see the following picture) and if you have mistakenly set the custom class for your ContentView or any of its subviews, it goes through another Nib loading process and stuck in a recursive infinite loop.

To do it the right way, you should only set your custom view class for the view in Placeholder’s part. Please see 1 and 2 in the following picture.

In this picture I have defined a custom class named CardView.

enter image description here

like image 23
Iman Avatar answered Sep 30 '22 20:09

Iman


You just defined the way to build a TestUIView that contains a TestUIView that contains a TestUIView that contains a TestUIView...

Your don't have to call

let view = NSBundle.mainBundle().loadNibNamed("TestUIView", owner: self, options: nil).first as! TestUIView

from

init?(coder aDecoder: NSCoder)

This way you are creating an infinite loop because loadNibNamed will automatically call the init?(coder aDecoder: NSCoder).

Just remove these lines

let view = NSBundle.mainBundle().loadNibNamed("TestUIView", owner: self, options: nil).first as! TestUIView
self.addSubview(view)
like image 31
Luca Angeletti Avatar answered Sep 30 '22 20:09

Luca Angeletti