简体   繁体   English

从 xib 文件加载 ViewController

[英]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 OwnerFoo ,而不是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上面的按钮现在连接到控制器但是当我评论出口时在此处输入图片说明

my app crashes我的应用程序崩溃在此处输入图片说明

在此处输入图片说明

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM