Reputation: 2425
I am trying to write a custom segue and have come across this error
Unbalanced calls to begin/end appearance transitions for UIViewController: 0x176c0bd0
The help button is connected to the almost empty ViewController - and the exit button unwinds the segue
All the controllers are embedded in a navigation Controller.
I've read through various posts here where people have encountered the same problem, but the solution varies a lot, and I still haven't found the right solution. I think it is because I am calling the custom segue from within a Navigation Controller, but that my code doesn't reflect that. I've followed this tutorial to create the custom segue http://blog.dadabeatnik.com/2013/10/13/custom-segues/
The initial controller has the following methods:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue isKindOfClass:[ICIHelpSegue class]]) {
((ICIHelpSegue *)segue).originatingPoint = self.help.center;
}
}
- (IBAction)unwindFromViewController:(UIStoryboardSegue *)sender {
}
- (UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController *)toViewController fromViewController:(UIViewController *)fromViewController identifier:(NSString *)identifier {
ICIUnwindHelpSegue *segue = [[ICIUnwindHelpSegue alloc] initWithIdentifier:identifier source:fromViewController destination:toViewController];
segue.targetPoint = self.help.center;
return segue;
}
The ICIHelpSegue class is the following interface:
@interface ICIHelpSegue : UIStoryboardSegue
@property CGPoint originatingPoint;
@property CGPoint targetPoint;
@end
And the implementation file looks like this:
@implementation ICIHelpSegue
- (void)perform {
UIViewController *sourceViewController = self.sourceViewController;
UIViewController *destinationViewController = self.destinationViewController;
UINavigationController *navigationController = sourceViewController.navigationController;
[navigationController.view addSubview:destinatiionViewController.view]
// Transformation start scale
destinationViewController.view.transform = CGAffineTransformMakeScale(0.05, 0.05);
// Store original centre point of the destination view
CGPoint originalCenter = destinationViewController.view.center;
// Set center to start point of the button
destinationViewController.view.center = self.originatingPoint;
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
// Grow!
destinationViewController.view.transform = CGAffineTransformMakeScale(1.0, 1.0);
destinationViewController.view.center = originalCenter;
}
completion:^(BOOL finished){
[destinationViewController.view removeFromSuperview]; // remove from temp super view
[navigationController presentViewController:destinationViewController animated:NO completion:NULL]; // present VC
}];
}
@end
Any ideas why this error occurs? What it means? And how to solve it?
Upvotes: 2
Views: 2623
Reputation: 1026
I have the same error. The issue appears to be related to the fact that removeFromSuperview is called in the same run loop as the call to presentViewController:animated:completion for the same viewController/view.
One thing you can do to get rid of this warning is to present the view controller after a delay:
completion:^(BOOL finished)
{
destinationViewController.view removeFromSuperview];
[navigationController performSelector:@selector(presentViewController:) withObject:destinationViewController afterDelay:0];
}];
}
-(void)presentViewController:(UIViewController*)viewController
{
[[self presentViewController:viewController animated:NO completion:nil];
}
However, both this method and the one with the warning will sometimes have a flicker because there is one frame where the view has been removed from the superview, but not presented yet.
To get around this issue, you can create a snapshot view of the destination view controller, and add that to the view hierarchy in place of the actual destinationViewController's view, and then remove it AFTER the destinationViewController has been presented:
completion:^(BOOL finished)
{
UIView * screenshotView = [destinationViewController.view snapshotViewAfterScreenUpdates:NO];
screenshotView.frame = destinationViewController.view.frame;
[destinationViewController.view.superview insertSubview:screenshotView aboveSubview: destinationViewController.view];
[destinationViewController.view removeFromSuperview];
[self performSelector:@selector(presentViewControllerRemoveView:) withObject:@[destinationViewController, screenshotView] afterDelay:0];
}];
}
-(void)presentViewControllerRemoveView:(NSArray *)objects
{
UIViewController * viewControllerToPresent = objects[0];
UIView * viewToRemove = objects[1];
[self presentViewController:viewControllerToPresent
animated:NO
completion:
^{
[viewToRemove removeFromSuperview];
}];
}
Upvotes: 7