【问题标题】:Loading ViewController from xib file从 xib 文件加载 ViewController
【发布时间】:2016-08-31 00:05:30
【问题描述】:

我有一个 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 类与键 XXX 的键值编码不兼容。

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

【问题讨论】:

  • 你能看到完整的代码吗
  • @bluenowhere 检查您已创建并与组件连接的所有插座。确保您的.xib 文件中的connection inspector 中的Outlets 中不应有任何感叹号。
  • bluenowhere:你找到答案了吗?
  • 我相信前两种方法将您的“MyViewController”类初始化为 UIViewController,并且没有正确连接插座和操作,因此应用程序在试图找到它们时崩溃。使用您的类的构造函数进行初始化会将类出口连接到 nib,以便一切正常运行。

标签: ios swift initialization xib viewcontroller


【解决方案1】:

试试下面的代码,

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

这会起作用。

【讨论】:

  • 请不要只用代码解释什么是错误以及您的代码如何帮助解决它:)
  • 是的,您可以看到编写代码的不同技能。有时它不允许在一行代码内进行初始化。
【解决方案2】:

问题不在于方法...您可能为某些 uielement 连接了一个插座(XXX),并已将其从相应的控制器中删除...我在下面添加示例...

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

我的应用崩溃了

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

【讨论】:

    【解决方案3】:

    注意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。所以,它会抛出异常。

    【讨论】:

      【解决方案4】:

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

      【讨论】:

      • @Woodstock:有点!这是对“如何从 XIB 文件加载 ViewController 的布局”问题的正确答案。但是,最初的问题是模棱两可的,因为 OP 似乎没有区分 (1) 从 XIB 加载以编程方式实例化的 ViewController 的布局 (View) 和 (2) 加载 ViewController 实例 itself来自 XIB。 AechoLiu的答案是对第二种解释的正确答案:-)
      • 如果您的 vc 名称与您可以使用的 xib 文件相同(nibName:nil,bundle:nil),它将起作用
      • 我收到错误loaded the "..." nib but the view outlet was not set.
      【解决方案5】:

      我遇到了同样的问题。自动生成的 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)
              }
      

      【讨论】:

        【解决方案6】:
        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()
        

        【讨论】:

        • 这是避免一堆重复代码的好方法!请注意,nib 文件的名称需要与类的名称相同。
        • 当然。 nib文件名需要和类名一致。
        【解决方案7】:

        @AechoLiu 的回答很棒。我有同样的问题,并通过以下修复进行了回答。

        问题:

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

        修复:

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

        我不小心将我的 Nib 文件转换到了错误的 Clas (NSViewController),尽管它已正确连接到 .xib 文件中。

        【讨论】:

          【解决方案8】:

          为 Swift 5 更新

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

          【讨论】:

          • 它正在为 myVC 返回一个 nil 值,代码中缺少某些内容,请尝试添加完整的代码 sn-p :)
          【解决方案9】:

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

          然后我像

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

          【讨论】:

          【解决方案10】:

          UIButton@IBAction 连接起来,并将以下代码添加到操作方法中,以呈现在.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.")
              }
          }
          

          【讨论】:

          • ViewControllerInXib 不存在。
          【解决方案11】:

          在 Swift5 中工作

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

          【讨论】:

          • 使用 Swift 5 与之前的版本没有区别。这与其他答案相同。
          【解决方案12】:
          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()
          }
          

          }

          【讨论】:

            【解决方案13】:

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

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

            把我扔了

            无法在包中加载 NIB:'NSBundle ... 名称为 '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 类名应该相同才能正常工作。

            【讨论】:

              【解决方案14】:

              你可以使用这个小的 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()
              

              【讨论】:

                猜你喜欢
                • 2017-12-09
                • 1970-01-01
                • 2021-04-11
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-08-13
                • 2023-04-06
                • 1970-01-01
                相关资源
                最近更新 更多