簡體   English   中英

從 xib 文件加載 ViewController

[英]Loading ViewController from xib file

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

我嘗試了不同的方法來加載這個視圖控制器,包括:

//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:]: 此類不是密鑰 XXX 的密鑰值編碼兼容。

這些加載方法有什么問題?

斯威夫特 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)
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()

文件所有者

注意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 the `self` parameter.
let myVC = NSBundle.mainBundle().loadNibNamed("MyViewController", owner: self, options: nil)[0] as? MyViewController

它將self分配為owner 因此, File's OwnerFoo ,而不是MyViewController 然后,對於Foo類,那些IBOutlet不能連接到Foo 所以,它拋出異常。

我有同樣的問題。 自動生成的 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)
        }

問題不在於方法...您可能已經為某些 uielement 連接了一個插座(XXX)並將其從相應的控制器中刪除...我在下面添加示例... 在此處輸入圖片說明

上面的按鈕現在連接到控制器但是當我評論出口時在此處輸入圖片說明

我的應用程序崩潰在此處輸入圖片說明

在此處輸入圖片說明

所以嘗試找到viewcontroller中缺少但在xib文件中的outlet(xxx)。希望它有幫助:)

試試下面的代碼,

//1

let nib = UINib(nibName: "MyViewController", bundle:nil)
myVC = nib.instantiateWithOwner(self, options: nil)[0] as? MyViewController

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

這將起作用。

@AechoLiu 的回答很棒。 我有同樣的問題,並通過以下修復回答了它。

問題:

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

修復:

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

我不小心將我的 Nib 文件轉換為錯誤的 Clas ( NSViewController ),盡管它在 .xib 文件中正確連接。

為 Swift 5 更新

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

UIButton@IBAction連接@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.")
    }
}
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()
}

}

這個擴展功能對我不起作用。

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類的名稱應該是相同的,它的工作。

你可以使用這個小的 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)
    }
}

像這樣使用

let controller = CustomViewController.loadController()

我刪除了文件所有者的類名並將其設置為第一個視圖的類名。 然后我必須為我將要使用的組件設置出口。

然后我加載了那個視圖類

let myViewController = Bundle.main.loadNibNamed("MyViewController", owner: self, options: nil)?.first as! MyViewController
view.addSubview(myViewController)

在 Swift5 中工作

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM