从xib文件加载ViewController

时间:2016-05-05 09:05:52

标签: ios swift initialization xib viewcontroller

我有一个MyViewController.swift和一个MyViewController.xib来展示MyViewController的布局。

我尝试了不同的方法来加载这个视图控制器,包括:

//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)

第三个是唯一成功的初始化,但前两个导致错误:

  

因未捕获的异常'NSUnknownKeyException',

而终止应用      

原因:'[setValue:forUndefinedKey:]:this   class不是键码XXX的键值编码。

这些加载方法有什么问题?

13 个答案:

答案 0 :(得分:62)

Swift 3

let myViewController = MyViewController(nibName: "MyViewController", bundle: nil)
self.present(myViewController, animated: true, completion: nil)

或推入导航控制器

self.navigationController!.pushViewController(MyViewController(nibName: "MyViewController", bundle: nil), animated: true)

答案 1 :(得分:11)

File's Owner

注意File's Owner。在您的情况下,File's Owner必须为MyViewController,或sub-class

以下代码,如果它在类Foo中执行。

// If `self` is an instance of `Foo` class.
// In this case, `File's Owner` will be a `Foo` instance due to `self` parameter.
let myVC = NSBundle.mainBundle().loadNibNamed("MyViewController", owner: self, options: nil)[0] as? MyViewController

它将self指定为owner。因此,File's OwnerFoo,而不是MyViewController。然后,对于Foo课程,这些IBOutlet无法连接到Foo。所以,它会抛出异常。

答案 2 :(得分:2)

问题不在于方法......你可能已经为一些uielement连接了一个插座(XXX)并将其从相应的控制器中删除了......我在下面添加了例子...... enter image description here < / p>

上面的按钮现在连接到控制器,但是当我评论插座时 enter image description here

我的应用崩溃了 enter image description here

enter image description here

所以尽量找到viewcontroller中缺少的outlet(xxx)但是在xib文件中。希望它有帮助:)

答案 3 :(得分:2)

我遇到了同样的问题。自动生成的xib中有一个UIView。您必须删除视图,将新视图控制器添加到xib,将视图控制器类设置为所需的视图控制器类,然后连接插座。完成所有这些后,您可以使用上面提供的代码来获取此视图控制器的实例,如下所示:

if let menuVC = Bundle.main.loadNibNamed("MenuViewController", owner: nil, options: nil)?.first as? MenuViewController {
            menuVC.profileType = profileType
            vc.present(menuVC, animated: true, completion: nil)
        }

答案 4 :(得分:2)

extension UIViewController {
    static func loadFromNib() -> Self {
        func instantiateFromNib<T: UIViewController>() -> T {
            return T.init(nibName: String(describing: T.self), bundle: nil)
        }

        return instantiateFromNib()
    }
}

按以下方式使用它:-

let testVC = TestVC.loadFromNib()

答案 5 :(得分:0)

@AechoLiu的回答很好。我有相同的问题,并使用以下修复程序予以回答。

问题:

let vc1 = NSViewController(nibName: YDNibIdentifier.myplainvc, bundle: nil)

修复:

let vc1 = MyPlainViewController(nibName: YDNibIdentifier.myplainvc, bundle: nil)

尽管我已将Nib文件正确连接到.xib文件中,但还是意外地将其Nib文件转换为错误的Clas(NSViewController)。

答案 6 :(得分:0)

已为Swift 5更新

        let myVC = Bundle.main.loadNibNamed("MyViewController", owner: self, options: nil)![0] as? MyViewController

答案 7 :(得分:0)

UIButton@IBAction连接起来,并将以下代码添加到action方法中,以显示在.xib文件中设置的新UIViewController

@IBAction func handleButtonAction(_ sender: UIButton) {
    let viewControllerInXib = ViewControllerInXib(nibName: "ViewControllerXibName", bundle: nil)
    present(viewControllerInXib, animated: true)
}

要通过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.")
    }
}

答案 8 :(得分:0)

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()
}

}

答案 9 :(得分:0)

这个扩展功能对我不起作用。

static func loadFromNib() -> Self {
    func instantiateFromNib<T: UIViewController>() -> T {
        return T.init(nibName: String(describing: T.self), bundle: nil)
    }
    return instantiateFromNib()
}

它把我扔了

<块引用>

无法在包中加载 NIB:'NSBundle ... with name 'UIViewController'

所以,我把它改成了这个并让它工作了。

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))
}

请记住,您的 .xib 文件和 .swift 类名应该相同才能正常工作。

答案 10 :(得分:-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

let nib : NSArray = NSBundle.mainBundle().loadNibNamed("MyViewController", owner: self, options: nil)
myVC = nib.objectAtIndex(0) as? MyViewController

这样可行。

答案 11 :(得分:-1)

我删除了文件所有者的类名,并将其设置为第一个视图的类名。然后,我必须为要使用的组件设置插座。

然后我像

那样加载了该视图类
let myViewController = Bundle.main.loadNibNamed("MyViewController", owner: self, options: nil)?.first as! MyViewController
view.addSubview(myViewController)

答案 12 :(得分:-2)

在 Swift5 中使用

self.navigationController!.pushViewController(MyViewController(nibName: "MyViewController", bundle: nil), animation: true)