12

I have created a custom UIView in MySample.xib. I have added the class MyView to the File Owner of xib.

MyView.swift

class MyView: UIView {

    @IBOutlet var view: UIView!

    override init(frame: CGRect) {
        super.init(frame: frame)

        setup()
    }

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

        setup()
    }

    func setup() {
        NSBundle.mainBundle().loadNibNamed("MySample", owner: self, options: nil)            
        self.addSubview(self.view)
    }
}

I am now loading this MyView from MyController file like this:

MyController.swift

class MyController: UIViewController {
    init() {
        super.init(nibName: nil, bundle: nil)

        view.addSubview(MyView())

    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

Now to display this view, I am using to following code from another controller's UIButton:

presentViewController(MyController(), animated: true, completion: nil)

This does display the view on screen. But the problem is, it doesn't accept any user interaction. In my custom view, I have a UITableView which does display the data but it doesn't scroll or get tapped due to lack of user interaction.

Any idea what I am doing wrong?

Forge
  • 6,538
  • 6
  • 44
  • 64
codelearner
  • 1,354
  • 1
  • 16
  • 32
  • Have you used the view hierarchy inspector to make sure nothing is on top of your custom view? – EmilioPelaez Apr 10 '16 at 23:14
  • @EmilioPelaez Yes I have checked it, nothing is on top of it. – codelearner Apr 10 '16 at 23:20
  • What happens if you override `touchesBegan...` on `MyView`? Does it get called? Is `userInteractionEnabled` true? – EmilioPelaez Apr 10 '16 at 23:22
  • @EmilioPelaez Nothing happens. It never get into that `touchesBegan` function. `userInteraction` on the view is also enabled. – codelearner Apr 10 '16 at 23:27
  • @EmilioPelaez I have tried using `touchesBegan` on `MyController` and it does work. But it doesn't work in `MyView`. In my code above I have added it as a subview in `MyController`. – codelearner Apr 10 '16 at 23:48
  • http://stackoverflow.com/questions/24370061/assign-xib-to-the-uiview-in-swift/24370553#24370553 – holex Apr 11 '16 at 08:40

3 Answers3

22

There are some unnecessary things in your example.

I am still not sure what are you trying to do, but if you want to add a custom view from xib to your view controller then:

  1. Create a view in a xib file , you don't need to override init , and you can't init view from xib using the default init UIView() , so please remove init method from your MyView class.

  2. In your xib make sure that your view that you see in the IB is of the class type you want to use (i guess MyView class).

  3. In your view controller init the view like this:

    class MyController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            //Get all views in the xib
            let allViewsInXibArray = NSBundle.mainBundle().loadNibNamed("MySample", owner: self, options: nil)
    
            //If you only have one view in the xib and you set it's class to MyView class
            let myView = allViewsInXibArray.first as! MyView
    
            //Set wanted position and size (frame)
            myView.frame = self.view.bounds
    
            //Add the view
            self.view.addSubview(myView)
    
            //TODO: set wanted constraints.
        }
    }
    
Forge
  • 6,538
  • 6
  • 44
  • 64
Oleg Sherman
  • 2,772
  • 1
  • 21
  • 20
  • 2
    Now I am receiving this error: `*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key label.'` – codelearner Apr 11 '16 at 07:30
  • You probably have bad connections in your xib, i suggest you to start with a new xib if possible, first create new xib , set the view's class to the relevant view class , set some background color , and see that it work. – Oleg Sherman Apr 11 '16 at 08:19
  • Instead of using `self` as owner, have to use `MyView()` to transfer all events to MyView class to which the view is linked. – codelearner Apr 11 '16 at 08:38
  • It worked with using "self" as file owner, perfect answer for such question so far. – vipsk Jun 21 '17 at 20:57
2

You don't have to re-instantiate this twice already if you using the design pattern.

It's so simple. Just write:

class MyController: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()

    //Get all views in the xib
    let view = MyView() 
    self.view.addSubview(myView)

    //TODO: set wanted constraints.
}}

And It will work.

Tim Diekmann
  • 7,755
  • 11
  • 41
  • 69
  • Whilst this may theoretically answer the question, [it would be preferable](//meta.stackoverflow.com/q/8259) to include the essential parts of the answer here, and provide the link for reference. – Tim Diekmann Jun 03 '18 at 16:03
0

Instead of linking xib File's Owner class to MyView, I have to change the class of root view in xib to MyView. Then based on @Oleg Sherman code, it works perfectly with small changes of adding MyView() as owner to get all it's events, otherwise it will throw an error this class is not key value coding-compliant for the key ****.:

let allViewsInXibArray = NSBundle.mainBundle().loadNibNamed("MySample", owner: MyView(), options: nil)

Using File's Owner class to MyView is only required when you have to use the xib in Storyboard.

Not sure if there is a workaround to use File's Owner class to MyView when programmatically loading xib from custom controller like in my original question.

codelearner
  • 1,354
  • 1
  • 16
  • 32
  • in my case...this works for me...i just change my owner to my xib class . : let mCuentasView = Bundle.main.loadNibNamed("CajaAhorroView", owner: self.mContainerCuenta, options: nil)![0] as! UIView self.mContainerView.addSubview(mCuentasView) mCuentasView.frame = self.mContainerView.bounds – xhinoda Dec 26 '17 at 18:55