[英]Loading ViewController from xib file
I had a MyViewController.swift
and a MyViewController.xib
presenting the layout of MyViewController.我有一个
MyViewController.swift
和一个MyViewController.xib
展示MyViewController.xib
的布局。
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',
由于未捕获的异常“NSUnknownKeyException”而终止应用程序,
reason: '[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key XXX.
原因: '[ setValue:forUndefinedKey:]: 此类不是密钥 XXX 的密钥值编码兼容。
What's wrong with those loading methods?这些加载方法有什么问题?
Swift 3斯威夫特 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)
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()
Notice the File's Owner
.注意
File's Owner
。 In your case, the File's Owner
must be MyViewController
, or its sub-class
.在您的情况下,
File's Owner
必须是MyViewController
或其sub-class
。
And the following code, if it executes in class Foo
.下面的代码,如果它在类
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
.它将
self
分配为owner
。 So, the File's Owner
is Foo
, not MyViewController
.因此,
File's Owner
是Foo
,而不是MyViewController
。 Then, for Foo
class, those IBOutlet
cannot be connected to Foo
.然后,对于
Foo
类,那些IBOutlet
不能连接到Foo
。 So, it throws exception.所以,它抛出异常。
I had the same problem.我有同样的问题。 The automatically generated xib had a UIView in it.
自动生成的 xib 中有一个 UIView。 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.
您必须删除视图,将新的视图控制器添加到 xib,将视图控制器类设置为您想要的类,然后连接插座。 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)
}
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...问题不在于方法...您可能已经为某些 uielement 连接了一个插座(XXX)并将其从相应的控制器中删除...我在下面添加示例...
the above button is connected to controller now but when i comment outlet上面的按钮现在连接到控制器但是当我评论出口时
so try to find outlet(xxx) that is missing from viewcontroller but is in xib file.Hope it helps :)所以尝试找到viewcontroller中缺少但在xib文件中的outlet(xxx)。希望它有帮助:)
Try below code,试试下面的代码,
//1 //1
let nib = UINib(nibName: "MyViewController", bundle:nil)
myVC = nib.instantiateWithOwner(self, options: nil)[0] as? MyViewController
OR或
myVC = nib.instantiateWithOwner(self, options: nil).first as? MyViewController
//2 //2
let nib : NSArray = NSBundle.mainBundle().loadNibNamed("MyViewController", owner: self, options: nil)
myVC = nib.objectAtIndex(0) as? MyViewController
This will work.这将起作用。
@AechoLiu's answer is great. @AechoLiu 的回答很棒。 I had the same question and answered it with the below fix.
我有同样的问题,并通过以下修复回答了它。
Problem:问题:
let vc1 = NSViewController(nibName: YDNibIdentifier.myplainvc, bundle: nil)
Fix:修复:
let vc1 = MyPlainViewController(nibName: YDNibIdentifier.myplainvc, bundle: nil)
I had accidentally cast my Nib file to the wrong Clas ( NSViewController ), despite having it connected correctly inside the .xib file.我不小心将我的 Nib 文件转换为错误的 Clas ( NSViewController ),尽管它在 .xib 文件中正确连接。
为 Swift 5 更新
let myVC = Bundle.main.loadNibNamed("MyViewController", owner: self, options: nil)![0] as? MyViewController
Connect the UIButton
with an @IBAction
and add the following code to the action method to present a new UIViewController
that is set up inside a .xib file.将
UIButton
与@IBAction
连接@IBAction
,并将以下代码添加到 action 方法中,以显示在 .xib 文件中设置的新UIViewController
。
@IBAction func handleButtonAction(_ sender: UIButton) {
let viewControllerInXib = ViewControllerInXib(nibName: "ViewControllerXibName", bundle: nil)
present(viewControllerInXib, animated: true)
}
To navigate via UINavigationController
you should use this method:要通过
UINavigationController
导航,您应该使用此方法:
@IBAction func handleButtonAction(_ sender: UIButton) {
let viewControllerInXib = ViewControllerInXib(nibName: "ViewControllerXibName", bundle: nil)
if let navigationController = navigationController {
navigationController.pushViewController(viewControllerInXib, animated: true)
} else {
print("Navigation controller unavailable! Use present method.")
}
}
public extension UIViewController {
static func loadNib() -> Self {
func instantiateFromNib<T: UIViewController>() -> T {
return T.init(nibName: String(describing: T.self), bundle: Bundle.init(for: Self.self))
}
return instantiateFromNib()
}
} }
This extension function didn't work for me.这个扩展功能对我不起作用。
static func loadFromNib() -> Self {
func instantiateFromNib<T: UIViewController>() -> T {
return T.init(nibName: String(describing: T.self), bundle: nil)
}
return instantiateFromNib()
}
It was throwing me它扔给我
Could not load NIB in bundle: 'NSBundle ... with name 'UIViewController'
无法在包中加载 NIB:'NSBundle ... with name 'UIViewController'
So, I changed it to this and got it working.所以,我把它改成这个并让它工作。
static func instantiateFromNib<T: UIViewController>() -> T {
// It is going to return YourAppName.YourClassName
let classDescription = classForCoder().description()
// Replacing YourAppName with Empty string
let nibFileName = classDescription.replacingOccurrences(of: "\(Bundle.main.infoDictionary?["CFBundleName"] as! String).", with: String())
return T.init(nibName: nibFileName, bundle: Bundle.init(for: Self.self))
}
Just keep that in mind your .xib
file and your .swift
class name should be the same for it to work.只要记住这一点,你
.xib
文件和你的.swift
类的名称应该是相同的,它的工作。
You can use this small UIViewController extension你可以使用这个小的 UIViewController 扩展
extension UIViewController {
class func loadController() -> Self {
return Self(nibName: String(describing: self), bundle: nil)
//Or You can use this as well
//Self.init(nibName: String(describing: self), bundle: nil)
}
}
Use like this像这样使用
let controller = CustomViewController.loadController()
I removed File owner's class name and set that to the class name of first view.我删除了文件所有者的类名并将其设置为第一个视图的类名。 And then I had to set outlets to the components which I'm going to use.
然后我必须为我将要使用的组件设置出口。
Then I loaded that view class like然后我加载了那个视图类
let myViewController = Bundle.main.loadNibNamed("MyViewController", owner: self, options: nil)?.first as! MyViewController
view.addSubview(myViewController)
Works this in Swift5在 Swift5 中工作
self.navigationController!.pushViewController(MyViewController(nibName: "MyViewController", bundle: nil), animated: true) self.navigationController!.pushViewController(MyViewController(nibName: "MyViewController", bundle: nil), 动画: true)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.