http://stackoverflow.com/questions/22676938/unbalanced-calls-to-begin-end-appearance-transitions-for-uiviewcontroller
Based on the Apple documentation I came up with the following method to switch between controllers in a containment controller. When there is an oldC
I am getting Unbalanced calls to begin/end appearance transitions for <...>
on the console.
- (void) showController:(UIViewController*)newC withView:(UIView*)contentView animated:(BOOL)animated
{
UIViewController *oldC = self.childViewControllers.firstObject;
if (oldC == newC) {
return;
}
[oldC willMoveToParentViewController:nil];
[self addChildViewController:newC];
newC.view.frame = (CGRect){ 0, 0, contentView.frame.size };
[contentView addSubview:newC.view];
if (animated && oldC != nil) {
oldC.view.alpha = 1.0f;
newC.view.alpha = 0.0f;
[self transitionFromViewController:oldC toViewController:newC duration:0.25f options:0 animations:^{
oldC.view.alpha = 0.0f;
newC.view.alpha = 1.0f;
} completion:^(BOOL finished) {
[oldC removeFromParentViewController];
[newC didMoveToParentViewController:self];
}];
} else {
oldC.view.alpha = 0.0f;
newC.view.alpha = 1.0f;
[oldC removeFromParentViewController];
[newC didMoveToParentViewController:self];
}
}
This is how I call it:
- (IBAction) buttonSignIn:(id)sender
{
[self showController:self.signInViewController withView:self.contentView animated:(sender != nil)];
}
- (IBAction) buttonSignUp:(id)sender
{
[self showController:self.signUpViewController withView:self.contentView animated:(sender != nil)];
}
To track this down I am logging the appearance transitions
-(void)beginAppearanceTransition:(BOOL)isAppearing animated:(BOOL)animated
{
[super beginAppearanceTransition:isAppearing animated:animated];
NSLog(@"**begin %@", self);
}
-(void)endAppearanceTransition
{
[super endAppearanceTransition];
NSLog(@"**end** %@", self);
}
This is what the log looks like:
] **begin <SignInViewController: 0x10c769a20>
] **begin <SignUpViewController: 0x10c768770>
] Unbalanced calls to begin/end appearance transitions for <SignUpViewController: 0x10c768770>.
] **end** <SignUpViewController: 0x10c768770>
] **end** <SignInViewController: 0x10c769a20>
Now I am a little puzzled. What's the problem here?
问题解决办法: Turns out transitionFromViewController:toViewController:duration:options:animations:completion:
also adds the view.
This method adds the second view controller’s view to the view hierarchy and then performs the animations defined in your animations block. After the animation completes, it removes the first view controller’s view from the view hierarchy.
Which means the addSubview
needs to be adjusted accordingly.
- (void) showController:(UIViewController*)newC withView:(UIView*)contentView animated:(BOOL)animated
{
UIViewController *oldC = self.childViewControllers.firstObject;
if (oldC == newC) {
return;
}
[oldC willMoveToParentViewController:nil];
[self addChildViewController:newC];
newC.view.frame = (CGRect){ 0, 0, contentView.frame.size };
if (animated && oldC != nil) {
oldC.view.alpha = 1.0f;
newC.view.alpha = 0.0f;
[self transitionFromViewController:oldC toViewController:newC duration:0.25f options:0 animations:^{
oldC.view.alpha = 0.0f;
newC.view.alpha = 1.0f;
} completion:^(BOOL finished) {
[oldC removeFromParentViewController];
[newC didMoveToParentViewController:self];
}];
} else {
[contentView addSubview:newC.view];
oldC.view.alpha = 0.0f;
newC.view.alpha = 1.0f;
[oldC removeFromParentViewController];
[newC didMoveToParentViewController:self];
}
}