Reputation: 2746
I have a parent VC with 3 children - Settings, Location and Diary.
Settings, Location & Diary are all accessed via IBActions based on their respective buttons.
When I go between Location and Diary, everything is fine. When I click Settings, it works, but when I click back to Location or Diary I get the dreaded must have a common parent view controller error. Funny thing is the exception says that the Diary and Location VC's don't share the same parent even though in that case I am clicking between Settings and either Diary or Location.
.m properties
@interface LPMainContentViewController ()
@property (weak, nonatomic) IBOutlet UIView *containerView;
@property (weak, nonatomic) IBOutlet UIButton *locationButton;
@property (weak, nonatomic) IBOutlet UIButton *diaryButton;
@property (weak, nonatomic) IBOutlet UIButton *settingsButton;
@property (strong, nonatomic) UIViewController *locationViewController;
@property (strong, nonatomic) UIViewController *diaryViewController;
@property (strong, nonatomic) UIViewController *settingsController;
- (IBAction)goToLocationView:(UIButton *)sender;
- (IBAction)goToDiaryView:(UIButton *)sender;
- (IBAction)goToSettings:(UIButton *)sender;
@end
I use if statements in the code to determine which was the previous child VC for the transition method and to set enabled on the button to YES or NO.
- (IBAction)goToLocationView:(UIButton *)sender {
if ([_diaryViewController isViewLoaded]){
[self cycleFromViewController:_diaryViewController toViewController:_locationViewController];
_locationButton.enabled = NO;
_diaryButton.enabled = YES;
}
else if ([_settingsController isViewLoaded]){
[self cycleFromViewController:_settingsController toViewController:_locationViewController];
_locationButton.enabled = NO;
_settingsButton.enabled = YES;
}
}
- (IBAction)goToDiaryView:(UIButton *)sender {
if ([_locationViewController isViewLoaded]){
[self cycleFromViewController:_locationViewController toViewController:_diaryViewController];
_locationButton.enabled = YES;
_diaryButton.enabled = NO;
}
else if ([_settingsController isViewLoaded]){
[self cycleFromViewController:_settingsController toViewController:_diaryViewController];
_diaryButton.enabled = NO;
_settingsButton.enabled = YES;
}
}
- (IBAction)goToSettings:(UIButton *)sender {
if ([_locationViewController isViewLoaded]){
[self cycleFromViewController:_locationViewController toViewController:_settingsController];
_locationButton.enabled = YES;
_settingsButton.enabled = NO;
}
else if ([_diaryViewController isViewLoaded]){
[self cycleFromViewController:_diaryViewController toViewController:_settingsController];
_diaryButton.enabled = YES;
_settingsButton.enabled = NO;
}
}
and here's the transition method pulled straight from the Apple docs
- (void) cycleFromViewController: (UIViewController*) oldVC
toViewController: (UIViewController*) newVC
{
[oldVC willMoveToParentViewController:nil];
[self addChildViewController:newVC];
newVC.view.frame = _containerView.bounds;
CGRect endFrame = _containerView.bounds;
[self transitionFromViewController: oldVC toViewController: newVC
duration: 0.0 options:0
animations:^{
newVC.view.frame = oldVC.view.frame;
oldVC.view.frame = endFrame;
}
completion:^(BOOL finished) {
[oldVC removeFromParentViewController];
[newVC didMoveToParentViewController:self];
}];
}
Upvotes: 3
Views: 867
Reputation: 119272
isViewLoaded
is the wrong thing to check. The view will get loaded once and then stick around, so you're probably choosing the wrong "current" view controller after a few cycles. Have another property to hold the current view controller instead, it will simplify your code and also actually work:
@property (weak, nonatomic) UIViewController *currentViewController;
You'll need to set this to whatever the initial child view controller is when you first set up the container view controller.
Then, change the goToXX
methods to be like the following:
- (IBAction)goToDiaryView:(UIButton *)sender {
self.settingsButton.enabled = YES;
self.locationButton.enabled = YES;
self.diaryButton.enabled = NO;
[self cycleFromViewController:self.currentViewController toViewController:self.diaryViewController];
}
Last of all, in your cycle
method, make sure you keep this property updated in the completion block of the transition:
completion:^(BOOL finished) {
[oldVC removeFromParentViewController];
[newVC didMoveToParentViewController:self];
self.currentViewController = newVC;
}];
Note that it is safer to use your properties rather than the _instanceVariables
. That's what they're there for.
Upvotes: 2