Laur Stefan
Laur Stefan

Reputation: 1579

Add child view controller to current view controller

I am trying to add a child view controller in code, to the current view controller from storyboard by using the next code:

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle: nil];
LogInTutorialViewController *lvc = [[LogInTutorialViewController alloc] init];
lvc = (LogInTutorialViewController *)[storyboard instantiateViewControllerWithIdentifier:@"LogInTutorialViewControllerID"];
[self displayContentController:lvc];

- (void) displayContentController: (LogInTutorialViewController*) content;
{

    //add as childViewController
    [self addChildViewController:content];
    [content didMoveToParentViewController:self];
    [content.view setFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
    [self.view addSubview:content.view];

}

The view seem to be displaying on the simulator at least but in console I get a lot or error:

 <Error>: CGContextSaveGState: invalid context 0x0. This is a serious error. This application, or a library it uses, is using an invalid context  and is thereby contributing to an overall degradation of system stability and reliability. This notice is a courtesy: please fix this problem. It will become a fatal error in an upcoming update.

And also the same description but different error:

CGContextSetLineWidth, CGContextSetLineJoin, CGContextSetLineCap, CGContextSetMiterLimit, CGContextSetFlatness, CGContextAddPath, CGContextDrawPath, CGContextRestoreGState

all these error get logged twice.

Does anyone know what I am doing wrong?

also I read a few posts and in some it was suggested to alloc and init the view controller before passing the data, I also tried that without any luck.

Upvotes: 21

Views: 56304

Answers (4)

atalayasa
atalayasa

Reputation: 3480

You can also create an extension for adding and removing UIViewController.

extension UIViewController {
    func addChildViewControllerWithView(_ childViewController: UIViewController, toView view: UIView? = nil) {
        let view: UIView = view ?? self.view
        childViewController.removeFromParent()
        childViewController.willMove(toParent: self)
        addChild(childViewController)
        childViewController.didMove(toParent: self)
        childViewController.view.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(childViewController.view)
        view.addConstraints([
            NSLayoutConstraint(item: childViewController.view!, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: 0),
            NSLayoutConstraint(item: childViewController.view!, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0),
            NSLayoutConstraint(item: childViewController.view!, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1, constant: 0),
            NSLayoutConstraint(item: childViewController.view!, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0)
        ])
        view.layoutIfNeeded()
    }

    func removeChildViewController(_ childViewController: UIViewController) {
        childViewController.removeFromParent()
        childViewController.willMove(toParent: nil)
        childViewController.removeFromParent()
        childViewController.didMove(toParent: nil)
        childViewController.view.removeFromSuperview()
        view.layoutIfNeeded()
    }
}

Whenever you'd like to add UIViewController in the viewDidLoad() method you need to call addChildViewControllerWithView(someVC)

Upvotes: 0

jason z
jason z

Reputation: 1377

Solution in Swift (Swift 4 at the time of this writing):

//load the view controller and add as child
storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
loginVC = storyboard.instantiateViewController(withIdentifier: "LOGIN")
addChildViewController(loginVC)

//make sure that the child view controller's view is the right size
loginVC.view.frame = contentView.bounds
contentView.addSubview(loginVC.view)

//you must call this at the end per Apple's documentation
loginVC.didMove(toParentViewController: self)

Notes:

  • Storyboard name is "Main".
  • View controller identifier in the storyboard is named "LOGIN".
  • This uses a storyboard to create load the view controller, but the same can be done programmatically. Just make sure the view is loaded into memory before you try and access the view's frame or you will get a crash (do something like present the view controller modally).

Upvotes: 8

Shahzaib Maqbool
Shahzaib Maqbool

Reputation: 1487

why you do not try this code for adding view i think this one is simple and easy..

self.loginView = [self.storyboard instantiateViewControllerWithIdentifier:@"LOGIN"];
[self addChildViewController:self.loginView];
[self.loginView.view setFrame:CGRectMake(0.0f, 0.0f, self.contentView.frame.size.width, self.contentView.frame.size.height)];
[self.contentView addSubview:self.loginView.view];
[self.loginView didMoveToParentViewController:self]; 

for further more information check this link.

Upvotes: 29

kirander
kirander

Reputation: 2256

didMoveToParentViewController must be the last.

Upvotes: 7

Related Questions