Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding a view controller as a subview in another view controller

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. enter image description here

like image 762
Srujan Simha Avatar asked Dec 03 '14 16:12

Srujan Simha


People also ask

How do I present a view controller from another view controller?

Start a segue from any object that implements an action method, such as a control or gesture recognizer. You may also start segues from table rows and collection view cells. Right-click the control or object in your current view controller. Drag the cursor to the view controller you want to present.


1 Answers

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.

enter image description here

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.

like image 121
Rob Avatar answered Oct 09 '22 00:10

Rob