Loading ViewController from xib file
I had a MyViewController.swift
and a MyViewController.xib
presenting the layout of MyViewController.
I tried different methods to load this view controller including:
//1
let myVC = UINib(nibName: "MyViewController", bundle:
nil).instantiateWithOwner(nil, options: nil)[0] as? MyViewController
//2
let myVC = NSBundle.mainBundle().loadNibNamed("MyViewController", owner: self, options: nil)[0] as? MyViewController
//3
let myVC = MyViewController(nibName: "MyViewController", bundle: nil)
The third one is the only successful initialisation, but the previous two are causing error:
Terminating app due to uncaught exception 'NSUnknownKeyException',
reason: '[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key XXX.
What's wrong with those loading methods?
Solution 1:
Swift 3
let myViewController = MyViewController(nibName: "MyViewController", bundle: nil)
self.present(myViewController, animated: true, completion: nil)
or push in navigation controller
self.navigationController!.pushViewController(MyViewController(nibName: "MyViewController", bundle: nil), animated: true)
Solution 2:
extension UIViewController {
static func loadFromNib() -> Self {
func instantiateFromNib<T: UIViewController>() -> T {
return T.init(nibName: String(describing: T.self), bundle: nil)
}
return instantiateFromNib()
}
}
Use it as the following:-
let testVC = TestVC.loadFromNib()
Solution 3:
Notice the File's Owner
. In your case, the File's Owner
must be MyViewController
, or its sub-class
.
And the following code, if it executes in class Foo
.
// If `self` is an instance of `Foo` class.
// In this case, `File's Owner` will be a `Foo` instance due to the `self` parameter.
let myVC = NSBundle.mainBundle().loadNibNamed("MyViewController", owner: self, options: nil)[0] as? MyViewController
It assigns self
as owner
. So, the File's Owner
is Foo
, not MyViewController
. Then, for Foo
class, those IBOutlet
cannot be connected to Foo
. So, it throws exception.
Solution 4:
I had the same problem. The automatically generated xib had a UIView in it. You have to delete the view, add new view controller to the xib, set the view controller class to the one you want and then connect the outlets. After all of this you can use the codes provided above to get an instance of this view controller, like this:
if let menuVC = Bundle.main.loadNibNamed("MenuViewController", owner: nil, options: nil)?.first as? MenuViewController {
menuVC.profileType = profileType
vc.present(menuVC, animated: true, completion: nil)
}
Solution 5:
The problem is not with the methods...you have probably kept an outlet(XXX) connected for some uielement and have removed it from corresponding controller...I am adding example below...
the above button is connected to controller now but when i comment outlet
my app crashes
so try to find outlet(xxx) that is missing from viewcontroller but is in xib file.Hope it helps :)