2

I've created a custom view using a .xib file for the layout. I would like to programatically create and add this view as a subview to a different view.

Subview class:

class Subview: UIView {

@IBOutlet var view: UIView!
@IBOutlet var titleLabel: UILabel!
@IBOutlet var textLabel: UILabel!

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

    Bundle.main.loadNibNamed("Subview", owner: self, options: nil)
    self.addSubview(view)
    view.frame = self.bounds
  }
}

I'm not sure how to go about it, the only constructor currently expects an instance of NSCoder which I don't have.

I've tried to give it an additional initialiser:

init(title: String, text: String) {
    titleLabel.text = title
    textLabel.text = text
    super.init(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
}

And then call it:

let v = Subview(title: dataSource[i].whatever, text: dataSource[i].bla)

But it fails when trying to unwrap the label outlets, which makes sense as the .xib hasn't been initialised.

I've already tried using a tableview and custom cells instead of programatically building the UI for the page, it doesn't really work because this is a detail page and I only have a single object as my data source instead of the array which the rowForIndexPath tableview delegate expects. I know I could write some mapper method to turn the object into an array of it's properties but I'd rather avoid that if possible.

Thanks.

4
  • Because in your case only the class has been initialized not the outlets as nib initialization was not assigned, you can try self = Bundle.main.loadNibNamed("Subview", owner: self, options: nil)?[0] Commented Mar 20, 2017 at 14:31
  • look ..stackoverflow.com/a/33946855/4003548. Commented Mar 20, 2017 at 14:41
  • stackoverflow.com/questions/35659714/… This should be helpfull Commented Mar 20, 2017 at 14:48
  • Thanks for the responses, when I try either solution I'm seeing this error when I try using Bundle.main.loadLibNamed: this class is not key value coding-compliant for the key, which I think is an issue with the outlets. I should also note, I can add the xib to my storyboard with no problems at all, I may need to create more than one which is why I need to figure out how to do it programatically. Commented Mar 20, 2017 at 14:51

3 Answers 3

4

1) Go to Subview.xib and make sure that the file owner is left empty.

enter image description here

Also, make sure that the class for your view is selected as Subview.

enter image description here

2) Get rid of the initializer, so:

class Subview: UIView {

    @IBOutlet var view: UIView!
    @IBOutlet var titleLabel: UILabel!
    @IBOutlet var textLabel: UILabel!

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

        Bundle.main.loadNibNamed("Subview", owner: self, options: nil)
        self.addSubview(view)
        view.frame = self.bounds
    }
}

should be:

class Subview: UIView {

    @IBOutlet var view: UIView!
    @IBOutlet var titleLabel: UILabel!
    @IBOutlet var textLabel: UILabel!
}

3) Initialize you view this way:

let view = UINib(nibName: "Subview", bundle: nil).instantiate(withOwner: nil, options: nil).first as! Subview

You can also check out these.

http://supereasyapps.com/blog/2014/12/15/create-an-ibdesignable-uiview-subclass-with-code-from-an-xib-file-in-xcode-6

How to initialise a UIView Class with a xib file in Swift, iOS

Good luck!

Sign up to request clarification or add additional context in comments.

1 Comment

+1 but the only issue I found with this, is that the bounds aren't set this way and the custom view is not displaying correctly.
1

If you need to handle IBOutlets I suggest you use a UIViewController as the owner of the xib instead of a UIView (when creating a UIViewController from File menu there is the option to create also a xib)

Then you can instantiate it this way in the parent view

    var subviewController: SubviewController?

    override func viewDidLoad() {
        super.viewDidLoad()

        subviewController = SubviewController(nibName: nil, bundle: nil)

        self.view.addSubview(subviewController!.view)

        //Remember to call the IBOutlets only after adding the view
        subviewController!.titleLabel.text = "This is the title" 

        subviewController!.view.frame = self.view.frame //Not suggested
        //Instead set constraints here
    }

Either way you have to set constraints or end using viewDidLayoutSubviews() as suggested in Swift: Add a xib into a UIView

Comments

0

Custom subclasses can be tricky, particularly when using xib files. With the code you've shown, it's not clear where you're going wrong - but yeah, probably losing the Outlet connections.

Here's a working example - includes Obj-C and Swift versions, including using the custom classes within Interface Builder. Specifically for what you're trying to do, look at the Swift3/SW3LoadFromXIB example:

https://github.com/DonMag/IBDesignInspect

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.