在另一个视图控制器中添加一个视图控制器作为子视图 [英] Adding a view controller as a subview in another view controller

查看:42
本文介绍了在另一个视图控制器中添加一个视图控制器作为子视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我找到了几个关于这个问题的帖子,但没有一个能解决我的问题.

像我一样说..

  1. 视图控制器A
  2. 视图控制器B

我尝试将 ViewControllerB 添加为 ViewControllerA 中的子视图,但是它抛出了类似fatal error:unwrapping an Optional value"之类的错误.

下面是代码...

视图控制器A

var testVC: ViewControllerB = ViewControllerB();覆盖 func viewDidLoad(){super.viewDidLoad()self.testVC.view.frame = CGRectMake(0, 0, 350, 450);self.view.addSubview(testVC.view);//加载视图后进行任何其他设置.}

ViewControllerB 只是一个带有标签的简单屏幕.

ViewControllerB

 @IBOutlet 弱无功测试:UILabel!覆盖 func viewDidLoad() {super.viewDidLoad()test.text = "Success"//在这里抛出错误致命错误:在解包可选值时意外发现 nil"}

编辑

根据用户回答的建议解决方案,ViewControllerA 中的 ViewControllerB 将离开屏幕.灰色边框是我为子视图创建的框架.

解决方案

几点意见:

  1. 当您实例化第二个视图控制器时,您正在调用 ViewControllerB().如果该视图控制器以编程方式创建其视图(这是不寻常的),那就没问题了.但是 IBOutlet 的存在表明第二个视图控制器的场景是在 Interface Builder 中定义的,但是通过调用 ViewControllerB(),你没有给故事板一个实例化的机会那个场景并连接所有的网点.因此,隐式解包的 UILabelnil,从而导致您的错误消息.

    相反,你想在 Interface Builder 中给你的目标视图控制器一个storyboard id",然后你可以使用 instantiateViewController(withIdentifier:) 来实例化它(并连接所有的 IB 插座).在 Swift 3 中:

    let controller = storyboard!.instantiateViewController(withIdentifier: "scene storyboard id")

    您现在可以访问此controllerview.

  2. 但是如果你真的想做 addSubview(即你没有过渡到下一个场景),那么你正在从事一种称为视图控制器包含"的实践.您不只是想简单地addSubview.你想做一些额外的容器视图控制器调用,例如:

    let controller = storyboard!.instantiateViewController(withIdentifier: "scene storyboard id")addChild(控制器)controller.view.frame = ...//或者,更好的是,关闭 `translatesAutoresizingMaskIntoConstraints`,然后为这个子视图定义约束view.addSubview(controller.view)controller.didMove(toParent: self)

    有关此原因的详细信息 .

    I have found few posts for this problem but none of them solved my issue.

    Say like I've..

    1. ViewControllerA
    2. ViewControllerB

    I tried to add ViewControllerB as a subview in ViewControllerA but, it's throwing an error like "fatal error: unexpectedly found nil while unwrapping an Optional value".

    Below is the code...

    ViewControllerA

    var testVC: ViewControllerB = ViewControllerB();
    
    override func viewDidLoad()
    {
        super.viewDidLoad()
        self.testVC.view.frame = CGRectMake(0, 0, 350, 450);
        self.view.addSubview(testVC.view);
        // Do any additional setup after loading the view.
    }
    

    ViewControllerB is just a simple screen with a label in it.

    ViewControllerB

     @IBOutlet weak var test: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        test.text = "Success" // Throws ERROR here "fatal error: unexpectedly found nil while unwrapping an Optional value"
    }
    

    EDIT

    With the suggested solution from the user answers, ViewControllerB in ViewControllerA is going off the screen. Grey border is the frame I have created for the subview.

    解决方案

    A couple of observations:

    1. When you instantiate the second view controller, you are calling ViewControllerB(). If that view controller programmatically creates its view (which is unusual) that would be fine. But the presence of the IBOutlet suggests that this second view controller's scene was defined in Interface Builder, but by calling ViewControllerB(), you are not giving the storyboard a chance to instantiate that scene and hook up all the outlets. Thus the implicitly unwrapped UILabel is nil, resulting in your error message.

      Instead, you want to give your destination view controller a "storyboard id" in Interface Builder and then you can use instantiateViewController(withIdentifier:) to instantiate it (and hook up all of the IB outlets). In Swift 3:

      let controller = storyboard!.instantiateViewController(withIdentifier: "scene storyboard id")
      

      You can now access this controller's view.

    2. But if you really want to do addSubview (i.e. you're not transitioning to the next scene), then you are engaging in a practice called "view controller containment". You do not just want to simply addSubview. You want to do some additional container view controller calls, e.g.:

      let controller = storyboard!.instantiateViewController(withIdentifier: "scene storyboard id")
      addChild(controller)
      controller.view.frame = ...  // or, better, turn off `translatesAutoresizingMaskIntoConstraints` and then define constraints for this subview
      view.addSubview(controller.view)
      controller.didMove(toParent: self)
      

      For more information about why this addChild (previously called addChildViewController) and didMove(toParent:) (previously called didMove(toParentViewController:)) are necessary, see WWDC 2011 video #102 - Implementing UIViewController Containment. In short, you need to ensure that your view controller hierarchy stays in sync with your view hierarchy, and these calls to addChild and didMove(toParent:) ensure this is the case.

      Also see Creating Custom Container View Controllers in the View Controller Programming Guide.


    By the way, the above illustrates how to do this programmatically. It is actually much easier if you use the "container view" in Interface Builder.

    Then you don't have to worry about any of these containment-related calls, and Interface Builder will take care of it for you.

    For Swift 2 implementation, see previous revision of this answer.

    这篇关于在另一个视图控制器中添加一个视图控制器作为子视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆