Using view controller containment, children lose parent

2.2k Views Asked by At

New iOS developer writing first commissioned app for iPhone.

Modally called parent view controller has six children which are transitioned using a segmented control in the parent. I am getting the error:

Children view controllers and must have a common parent view controller when calling -[UIViewController transitionFromViewController:toViewController:duration:options:animations:completion:]

when I press a second button, ie i can press any button after the parent is presented and it works. But the next time I press a new button, I get the crash above. Using NSLogs I have determined that the reason for the crash is that both the current and new child have lost their parent between button presses. I have no idea why. Relevent code for parent follows:

Interface code:

#import <UIKit/UIKit.h>
#import "WorksheetScrollViewController.h"
#import "Worksheet1ViewController.h"
#import "Worksheet2ViewController.h"
#import "Worksheet3ViewController.h"
#import "Worksheet4ViewController.h"
#import "WorksheetEndViewController.h"


@interface WorkSheetParentViewController : UIViewController
{
IBOutlet UISegmentedControl *segControl;
IBOutlet UIBarButtonItem *doneButton;
IBOutlet UIView *childContainerView;

WorksheetScrollViewController *wStart;
Worksheet1ViewController *w1; 
Worksheet2ViewController *w2;
Worksheet3ViewController *w3;
Worksheet4ViewController *w4;
WorksheetEndViewController *wEnd;

UIViewController *currentVC;
UIViewController *newVC;

}


-(void)initToolbar;
-(IBAction) doneButtonPressed:(id)sender;
-(IBAction) segControlChanged:(id)sender;

-(void)swapViewControllers;

Implementation code:

- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
wStart = [[WorksheetScrollViewController alloc        ]initWithNibName:@"WorksheetScrollViewController" bundle:nil];

[self addChildViewController:wStart];
wStart.view.frame=childContainerView.bounds;

[childContainerView addSubview:wStart.view];
[wStart didMoveToParentViewController:self];
currentVC = wStart;

}

- (IBAction) segControlChanged:(id)sender

{

NSLog(@"selected tab bar item:%i",segControl.selectedSegmentIndex);
switch (segControl.selectedSegmentIndex) {
    case 0:
        if (!wStart) {
            wStart = [[WorksheetScrollViewController alloc ]initWithNibName:@"WorksheetScrollViewController" bundle:nil];
        }
        newVC = wStart;
        break;

    case 1:
        if (!w1) {
            w1 = [[Worksheet1ViewController alloc ]initWithNibName:@"Worksheet1ViewController" bundle:nil];
        }
        newVC = w1;
        break;

    case 2:
        if (!w2) {
            w2 = [[Worksheet2ViewController alloc ]initWithNibName:@"Worksheet2ViewController" bundle:nil];
        }
        newVC = w2;
       break;

    case 3:
        if (!w3) {
            w3 = [[Worksheet3ViewController alloc ]initWithNibName:@"Worksheet3ViewController" bundle:nil];
        }
        newVC = w3;
        break;

    case 4:
        if (!w4) {
            w4 = [[Worksheet4ViewController alloc ]initWithNibName:@"Worksheet4ViewController" bundle:nil];
        }
        newVC = w4;
        break;

    case 5:
        if (!wEnd) {
            wEnd = [[WorksheetEndViewController alloc ]initWithNibName:@"WorksheetEndViewController" bundle:nil];
        }
        newVC = wEnd;
        break;


    default:
        break;
}
[self  swapViewControllers];


}

-(void)swapViewControllers
{
NSLog(@"top current VC parent = %@",currentVC.parentViewController);
NSLog(@"top new VC parent = %@",newVC.parentViewController);
[currentVC willMoveToParentViewController:nil];
newVC.view.frame=childContainerView.bounds;

[self addChildViewController:newVC];

NSLog(@"current VC parent = %@",currentVC.parentViewController);
NSLog(@"new VC parent = %@",newVC.parentViewController);
[self transitionFromViewController:currentVC
                  toViewController:newVC
                          duration:1.0
                           options:UIViewAnimationOptionTransitionCurlUp
                        animations:nil
                        completion:^(BOOL finished) {
                            [currentVC removeFromParentViewController];
                            [newVC didMoveToParentViewController:self];

                        }];
currentVC = newVC;
NSLog(@"bottom current VC parent = %@",currentVC.parentViewController);
NSLog(@"bottom new VC parent = %@",newVC.parentViewController);

}

Nslog results for pressing button 1, then button 2:

2013-08-26 14:49:07.245 Alveolar Gas iPhone[556:707] selected tab bar item:1
2013-08-26 14:49:07.251 Alveolar Gas iPhone[556:707] top current VC parent =      <WorkSheetParentViewController: 0x198da0>
2013-08-26 14:49:07.256 Alveolar Gas iPhone[556:707] top new VC parent = (null)
2013-08-26 14:49:07.437 Alveolar Gas iPhone[556:707] current VC parent = <WorkSheetParentViewController: 0x198da0>
2013-08-26 14:49:07.440 Alveolar Gas iPhone[556:707] new VC parent = <WorkSheetParentViewController: 0x198da0>
2013-08-26 14:49:07.460 Alveolar Gas iPhone[556:707] bottom current VC parent = <WorkSheetParentViewController: 0x198da0>
2013-08-26 14:49:07.462 Alveolar Gas iPhone[556:707] bottom new VC parent = <WorkSheetParentViewController: 0x198da0>
2013-08-26 14:49:13.984 Alveolar Gas iPhone[556:707] selected tab bar item:2
2013-08-26 14:49:33.912 Alveolar Gas iPhone[556:707] top current VC parent = (null)
2013-08-26 14:49:50.038 Alveolar Gas iPhone[556:707] top new VC parent = (null)
2013-08-26 14:55:36.149 Alveolar Gas iPhone[556:707] current VC parent = (null)
2013-08-26 14:55:36.153 Alveolar Gas iPhone[556:707] new VC parent = <WorkSheetParentViewController: 0x198da0>
2013-08-26 14:55:36.160 Alveolar Gas iPhone[556:707] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Children view controllers <Worksheet1ViewController: 0x1ea780> and <Worksheet2ViewController: 0x1403b0> must have a common parent view controller when calling -[UIViewController transitionFromViewController:toViewController:duration:options:animations:completion:]'
1

There are 1 best solutions below

0
On BEST ANSWER

I fixed it by moving currentVC = newVC; into the completion block. SwapViewControllers: now looks like this:

-(void)swapViewControllers
{
NSLog(@"top current VC parent = %@",currentVC.parentViewController);
NSLog(@"top new VC parent = %@",newVC.parentViewController);
[currentVC willMoveToParentViewController:nil];
newVC.view.frame=childContainerView.bounds;

[self addChildViewController:newVC];

NSLog(@"current VC parent = %@",currentVC.parentViewController);
NSLog(@"new VC parent = %@",newVC.parentViewController);
[self transitionFromViewController:currentVC
                  toViewController:newVC
                          duration:1.0
                           options:UIViewAnimationOptionTransitionCurlUp
                        animations:nil
                        completion:^(BOOL finished) {
                            [currentVC removeFromParentViewController];
                            [newVC didMoveToParentViewController:self];
                            currentVC = newVC;
                        }];

NSLog(@"bottom current VC parent = %@",currentVC.parentViewController);
NSLog(@"bottom new VC parent = %@",newVC.parentViewController);

}