Unbalanced calls to begin/end appearance transitions for <FirstViewController: 0x2a2c00> - iphone

I have this problem when I simulate my app, its not an error or a warning but it appears in my console, has anyone ever experienced this before?

In my case, this error occurs when you click two tabs in a tableview very fast.
The result causes wrong titlename, back button disappear. Someone mentioned that when you push a view, set animated:NO. The error will disappear but still causes some strange behavior. It pushes two views, then you need to back twice to get back the tableview screen.
Method I tried in order to resolve this problem:
add BOOL cellSelected;
in viewWillAppear cellSelected = YES;
in didselectcell delegate if (cellSelected){cellSelected = NO; do action ; }
This helps prevent clicking two different cells very fast.

In my case it happened when I triggered [self performSegueWithIdentifier:#"SomeIdentifier" sender:self]; within a UINavigationController item's viewDidLoad method.
Moving it into the viewDidAppear method solved the problem.
The reason very likely is that in viewDidLoad not all of the fancy animations have already been finished, whereas in viewDidAppear everything's done.

I have this problem too. I found two solutions to this problem:
You can see this solution above.
I found subclass from UINavigationController where this problem resolved. Buffered Navigation Controller

You should run your code in different loop to avoid this
double delayInSeconds = 0.1;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
// Put your code here
[self presentViewController:self.yourModalVC animated:YES completion:nil];
});

I had lot of problem with the same issue. I solved this by this way
1) You're not using UIViewController's designated initializer initWithNibName:bundle:. Try using it instead of just init.
2) set animated:YES to a NO, and that solved the problem.
eg. [self.navigationController pushViewController: viewController_Obj animated:NO];

I had the same issue using navigation controller and push other controllers to it.
I tried to use Buffered Navigation Controller and several other approaches, but it didn't work for me. After spending some time for figuring it out I noticed that this issue occurs if you trying to push new view controller while previous transaction (animation) in progress (about 0.5 sec duration I guess). Anyway, I made quick solution with delegating navigation controller and waiting for previous animation finishes.

Ensure that you do not forget to in -viewWillAppear, -viewDidAppear, -viewDidLoad, -viewWillDisappear, -viewDidDisappear to call proper super method in your overload of that methods.
For example in my case I mismatched method name like this:
-(void)viewDidAppear
{
[super viewDidDisappear];
//some code staff
..
}
notice that appear and disappear methods are mismatched

'Unbalanced calls to begin/end appearance transitions for '
Says an animation is started before the last related animation isn't done. So, are you popping any view controller before pushing the new one ? Or may be popping to root ? if yes try doing so without animation i.e. [self.navigationController popToRootViewControllerAnimated:NO];
And see if this resolves the issue, In my case this did the trick.

I had a similar problem that involved rewinding modal dialogs. Posted the solution here...
https://stackoverflow.com/a/38795258/324479
[Problem]
Nav Controller -> VC1 -Push--> VC2 -PopOver or Modal Segue--> VC3.
VC3 is unwinding back to VC1.
When the Segue from VC2 to VC3 is PopOver and Modal, the unwind ends in a warning: Unbalanced calls to begin/end appearance transitions for UIViewController"
If the Segue from VC to VC is push, the warning is gone.
[Solution]
It would be great if the unwind logic would take care of this. Maybe it's a bug, maybe not. Either way, the solution is to make VC2 (The controller that has the popup) the target of the rewind, then wait for it to finish appearing before popping up the nav controller. That ensures the rewind (reverse popup) animation has enough time to finish before moving further back. Even with the animations off, it still has to wait or else you get the error.
Your code for VC2 should be as follows. (Swift)
class VC2: UIViewController {
private var unwind = false
#IBAction func unwindToVC1(segue:UIStoryboardSegue) {
unwind = true
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if unwind {
self.navigationController?.popViewControllerAnimated(false)
}
}
}

I got this issue because I was calling a UIPrintInteractionController from a viewController without UITabbar, and neither UINavigationBar. It seems that the UIPrintInteractionController didn't get the correct printInteractionControllerParentViewController.
Implementing the method in the delegate and return the current rootViewController worked for me.
- (UIViewController*)printInteractionControllerParentViewController:(UIPrintInteractionController*)printInteractionController;

Swift 4
My issue was that I was presenting another VC before my current one finished to be rendered .
Solution was to present my nextVC after a quick delay.
WHAT YOU SHOULD NOT DO
override func viewDidLoad() {
super.viewDidLoad()
self.present(MyNextVC(), animated: true, completion: nil)
}
WHAT YOU SHOULD DO
override func viewDidLoad() {
super.viewDidLoad()
//Wait until the view finished to be constructed
perform(#selector(showMyNextVC), with: nil, afterDelay: 0.01)
}
#objc func showCityList() {
self.present(MyNextVC(), animated: true, completion: nil)
}

The situation can occur if you are adding a view with a modal view controller as a sub view. Best to use:
-(void) viewDidAppear:(BOOL)animated {
[self presentViewController:self.yourModalVC animated:YES completion:nil];
}
It is basically saying the view life cycle is not streamlined for those viewControllers you are trying to display then.

I have the similar problem when trying to do:
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:2] animated:YES];
in a function like - (void) popUpToLevelTwo; , and to put a return; at the end of function solves the problem

I also got this at
[self dismissModalViewControllerAnimated:YES];
I changed the YES to a NO, and that solved the problem.

i have same problem when i used navigationcontroller's pop method
In my app i use a separate logic for navigation controller,So avoided the use of navigation bar and it is always hidden. Then i use a custom view and notification for handling the backbutton and it's events. notification observers are registered and and not removed. So the notification fires twice, and it creates the above mentioned error. Check your code throughly for getting such fault's

For what it's worth, I got this same error when not including a call to [super viewDidLoad:animated] in my viewDidLoad override.

I also had this problem when I tapped a button from a NIB. It turns out I had accidentally wired the button to send an event to two IBAction methods, each of which did a pushViewController:animated:

I had some logic implemented to wait pushing the UIViewController until all data was downloaded. There was an error in this logic which caused to push the UIViewController too early while there was still another API call in progress.
It caused the same UIViewController to be pushed twice by the UINavigationController and gave this warning.

Reason For message: This message get displayed if and only if you are pushing/presenting another View controller from viewWillAppear,loadView,init or viewDidLoad method of current View Controller
Way to Remove error Message: Move your pushing/presenting code to viewDidAppear method will solve the issue

I had this problem when I forget to set Break; after pushing the view in a switch statement!
Like here:
case 1:{
SomeViewController *someViewController = [[SomeViewController alloc]initWithNibName:#"SomeViewController" bundle:Nil];
[self.navigationController pushViewController:someViewController animated:YES];
[someViewController release];
}
break; //Forgetting to set break here:

the reason behind the error " Unbalanced calls to begin/end appearance transitions" is when you navigate | segue twice at the same time

one solution would be,
[NSTimer scheduledTimerWithTimeInterval:0.05(or as required) target:self
selector:#selector(your_selector_method_to_push_the_view) userInfo:nil repeats:NO];

You can run into this if you try to dismiss a UIViewController before it is finished loading.
I had this message in the console and was focusing entirely on the UIViewController that was presenting the new UIViewController, without success. I finally discovered the problem was in the UIViewController I was presenting was dismissing itself because the user wasn't logged into their account.
Hope this helps someone.

This was a tough one for me:
I've overridden
override func shouldAutomaticallyForwardRotationMethods() -> Bool {
return true
}
without overriding:
override func shouldAutomaticallyForwardAppearanceMethods() -> Bool {
return true
}
in my window root navigation controller.
then a child navigation controller complained when pushing another view controller with the above mentioned warning.
The warning wasn't the worst,
the big problem was, that there the delegate of the child navigation controller weren't called anymore.
weired.

In my case I was fetching NSData from NSURL inside 'viewDidLoad' method.

Related

UINavigationController - Run Code Before Popping View Controller

I have a stack of UIViewController subclasses. Each modifies a NSManagedObject model. Many of them also present their own modal view controllers.
I need to save changes to the NSManagedObjectContext when a user either 'pops' the view controller or pushes the next view controller.
Currently, I'm hiding the default back button and setting my own UIBarButtonItem with a target of self and a custom action.
This works okay, but ideally, I want to use the default back button and run code before the pop. Is there a way I can run my own code before the pop?
(I'd prefer not to put code into viewWillDisappear as persisting to disk can be expensive and this method can also be triggered by modals being displayed by view controller.) Can it be done?
You can do it in viewDidDisappear, after checking that self is either 1) the second last element in self.navigationController.viewControllers (the case where the next VC just got pushed) or 2) self.navigationController is nil (the self VC just got popped).
Yes.. Navigation controller has a delegate which indicates when a view controller popped or pushed.. You can use that to do your task...
Add following method in your code:
- (void) viewWillDisappear:(BOOL)animated{
//your code here
}
I use viewWillDissappear to make any changes persistant.
If required i Use viewWillAppear to recoginze any changes (reload the data) that may have taken place while other puhed view controlers did their work.
For pop check isMovingFromParent in viewWillDisappear
func viewWillDisappear(_ animation:Bool){
super.viewWillDisappear(animation);
if isMovingFromParent {
// your code here
}
}

Presenting a ModalViewController inside a ModalViewController

I have a view which is presented as a modal view controller which takes username and password credentials. I want this view to check the delegate, and if the user hasn't previously set an unlock pin for the app, to then show the change pin view as a modal view controller. This is my code...
+(void)presentCredentialsViewController:(UIViewController *)vc{
CredentialsViewController *cvc = [[CredentialsViewController alloc] init];
[vc presentModalViewController:cvc animated:FALSE];
}
and then in CredentialsViewController
-(void)viewDidLoad{
[super viewDidLoad];
if([appDelegate.pin isEqualToString: #""]){
UserPrefsViewController *upvc = [[UserPrefsViewController alloc] init];
upvc.cancelButton.hidden = true;
[self presentModalViewController:upvc animated:FALSE];
}
}
But for some reason it doesn't work. The debugger steps through the code without error, never the less, the second modal view controller isn't displayed.
First, I would suggest checking that your appDelegate.pin is blank and not nil. If it is nil, the if statement would not be satisfied and your second ModalView would not be presented.
You may also want to try the previous suggestion, calling presentModalViewController from viewDidAppear, or setting a delay if leaving it in viewDidLoad. It is possible that the CredentialsViewController is trying to present the second view when it has not yet presented itself.
The if statement is being hit and the second PresentModalViewController is executing without error, but it just wasn't displaying. I did try putting the code in ViewDidAppear and a load of other places as well, such as applicationWillBecomeActive etc. Although not actually crashing the code, still none of these approaches would show the view controller. In the end I have opted for this:
start with pin of #""
on applicationDidEnterBackground check if pin has been set
if yes
PresentModalViewController: PinViewController
if no
do nothing
Bit of a hack but it will do for now. I suppose I should put some sort of notification in somewhere warning that the pin hasn't been set. The suggestion about the delay may possibly work I suppose. I might give it a go in the future. Thanks guys....points up!

iPhone UINavigation Issue - nested push animation can result in corrupted navigation bar

I keep getting the following errors:
2011-04-02 14:55:23.350 AppName[42430:207] nested push animation can result in corrupted navigation bar
2011-04-02 14:55:23.352 AppName[42430:207] nested push animation can result in corrupted navigation bar
2011-04-02 14:55:23.729 AppName[42430:207] Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.
2011-04-02 14:55:23.729 AppName[42430:207] Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.
Here is what I am doing. From a view controller, I call the following when a certain button is pushed:
EventsViewController *viewController = [[EventsViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
navController.navigationBar.tintColor = [UIColor blackColor];
[self presentModalViewController:navController animated:YES];
[viewController release];
[navController release];
Then, if a certain button is pushed in EventsController, I call:
SingleEventViewController *viewController = [[SingleEventViewController alloc] initWithEvent:[currentEvents objectAtIndex:indexPath.row]];
[self.navigationController pushViewController:viewController animated:YES];
[viewController release];
Then, if a certain button is pushed in SingleEventViewController, I call:
EventMapView* viewController = [[EventMapView alloc] initWithCoordinates];
[[self navigationController] pushViewController:viewController animated:YES];
[viewController release];
So yea, it's obvious that there's nested push animations, but isn't this the right way to go about it? I checked out Apple's DrillDownSave code and this appears to be how they're doing it. Does it matter that I use init methods instead of viewDidLoad methods?
Calling pushViewController before viewDidAppear is unsafe.
ACCIDENTLY TRIGGERING THE SAME SEGUE TWICE
Once in code, and once from interface builder, but both at the same time...
I was getting the same error as the rest of you. Only my problem was I was accidentally firing the same segue, twice. Once from interface builder, and once from within my code.
I have a UITableView. When a cell is selected, a segue in interface builder fires. Heres my problem, I had the segue set up to be directly fired off clicking the CELL ITSELf, inside interface builder, then in my code, I had under didSelectRowAtIndexPath, code that would fire that same segue... like so...
[self performSegueWithIdentifier:#"MySegue" sender:tableView];
That means when didSelectRowAtIndexPath gets called because a row was selected, it fires the segue with the above line of code. Then interface builder, also triggers the segue, because its connected directly to the cell object in interface builder. To stop interface builder from directly firing the segue. You have to connect the segue from the top of the view controller, not nested down inside coming off of the cell itself.
So if you are having this problem for the same reason as me, that is, you are calling the same segue twice, you can fix this by unlinking the connection from the CELL DIRECTLY, to your segue, and having the segue connection originate at the top of the table hierarchy in IB, rather than nested inside the cell. Connect the segue from you View Controller itself, to the segue. If you have done this correct, when you select the segue, it should highlight the ENTIRE view it is coming from, not just the cell.
Now Apples documentation states thus under the performSegueWithIdentifier:sender: reference:
Apps normally do not need to trigger segues directly. Instead, you configure an object in Interface Builder associated with the view controller, such as a control embedded in its view hierarchy, to trigger the segue. However, you can call this method to trigger a segue programmatically, perhaps in response to some action that cannot be specified in the storyboard resource file. For example, you might call it from a custom action handler used to process shake or accelerometer events.
In my case, I have a search button for my UITableView, and whether the segue is called when the search results table is present, or the normal table view is present, had to be determined. So I needed to trigger the segue directly.
So remove the embedded control from interface builder, and just stick it on the view controller itself, then trigger the segue in your code!
Now, no more double segues! And no more errors.
I had the same problem / error message as you did just now, was looking for a solution and ended up at this thread, however, for me I found that the solution is actually having only one animated:YES when doing a nested push (I put animated:YES only for the final push), hope this helps
cheers.
I've figured it out. Apparently if you call -pushViewController from outside of the -didSelectRowAtIndexPath method of a UITableViewDelegate, it doesn't work. Moving the call into that function worked. Weird.
I happened upon this same problem that resulted from a button in a nib being connected to two different actions. It tried loading both view controllers, thereby corrupting the stack.
What do you mean when you say you use init methods instead of viewDidLoad methods?
If you're pushing a new view controller before the old push has bad a chance to be actioned, you will get this sort of error. So putting certain code into init and doing things prematurely could certainly get you the error being reported.
At the point where init is being run on a view controller, the view hasn't been loaded yet!
Um I had this issue, and Im new to the whole iOS dev scene. But after looking at my connections inspector (with file's owner) in the interface builder i saw that as I had copied a button it had the previous buttons method assigned to it as well as the new method I had created. I guess that was where the nested aspect of my problem came from, as it was executing 2 different methods both of which pushed a view onto the Nav Controller. I know this has already been answered but I figured I would put this up just in case anyone else had a silly mistake like mine.
This has already been answered, but I thought this might help others as I got the same error but without using table views. I finally figured out the problem.
I had an existing button whose IBAction invoked a pushViewController. I had created a new button by copying the existing button. The new button also had an action that invoked pushViewController. When the new button was tapped (touch up inside) and the view controller was pushed, I got this error. I deleted the new button, created it from scratch, bound it to the existing outlets and actions, and the error went away.
Ran into the same problem. In my case I was missing a break in the switch statement so two segues were fired at the same time. Easy fix for me.
My problem had to do with the keyboard being active.
This was caused for me by pushing a ViewController from a textField's delegate method:
-(void)textFieldDidBeginEditing:(UITextField *)textField{
FilterLocationViewController *destViewController = (FilterLocationViewController *)[self.storyboard instantiateViewControllerWithIdentifier:#"FilterLocationViewController"];
[self.navigationController pushViewController:destViewController animated:YES];
}
By changing the code to this:
-(void)textFieldDidBeginEditing:(UITextField *)textField{
[_textFieldLocation resignFirstResponder]; //adding this line
FilterLocationViewController *destViewController = (FilterLocationViewController *)[self.storyboard instantiateViewControllerWithIdentifier:#"FilterLocationViewController"];
[self.navigationController pushViewController:destViewController animated:YES];
}
(adding the line [textField resignFirstResponder];) the problem went away.
Basically the lesson is that you shouldn't modify the navigationController stack if the keyboard is out.
Recently, I've faced the same problem. The reason was: -I was trying to pop view controller twice by mistake. you can check this crash by setting breakpoints on push and pop View controllers
1) Perhaps you could try passing the necessary variables as properties before pushing the UIViewController rather than using the init methods with parameters. Most likely you will need these parameters beyond your init method anyway.
Also, in your initWithCoordinates: method you are missing the parameters. Possibly your custom init methods are a part of the problem.
2) Just because you mentioned viewDidLoad -- this method is for initialization after a view has loaded . If you create the UIViewController in code, as it seems you do, you should use loadView to set up your subviews.
This was happening for me because of my UIControlEvents
[button addTarget:self action:#selector(callSecondView) forControlEvents:UIControlEventAllTouchEvents];
I had to change the UIControlEventAllTouchEvents to UIControlEventTouchUpInside or however you want your button to work if you had the issue because of a UIButton call.
My Solution was
[self performSelector:#selector(moveTo) withObject:nil
afterDelay:0.5];
Don't know about other's. I think most of the People using StoryBoard is facing such Problem. I am using XIB.
In my case The Problem Was, when I was moving to another view using push,
I was also using
[self.navigationController popViewControllerAnimated:YES];
in the ViewWillDisappear of the current View at the same time. Just remove it and it works fine.
I was using POP, because of the requirement and the Flow.
The Hierarchy was 1 -> 2 ->3
I was on view 2 and wanted to move to view 3. In that case I encountered this error.
In my case I was both setting the push segue from the storyboard and programatically. Hopefully that'll help anyone
I had this error message too, and the navigation bar and navigation controller transitions were weird. My setup was a bunch of Navigation Controllers embedded in a Tab bar Controller. The problem was that I didn't call super.viewDidLoad() in my Tab bar Controller implementation of viewDidLoad.
Calling super is something the docs clearly point out that you should do when overriding viewDidLoad, and I learned this the hard way.
Maybe this can help someone else too!
I know that this was answered, but it could help others.
I had the same problem, but it was caused because I was using a bad event for an info button.
I was using "UIControlEventAllTouchEvents" and this generated two push of the same view into the navigation controller. The correct event was "UIControlEventTouchUpInside". I'm new to iOS.
This resolves the problem:
https://github.com/nexuspod/SafeTransition
If you push (or pop) a view controller with animation(animated:YES) it doesn't complete right away, and bad things happen if you do another push or pop before the animation completes.
To reproduce this bug, try pushing or popping two view controllers at the same time. Example:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
UIViewController *vc = [[UIViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
}
You will receive this error:
2014-07-03 11:54:25.051 Demo[2840:60b] nested push animation can
result in corrupted navigation bar 2014-07-03 11:54:25.406
Demo[2840:60b] Finishing up a navigation transition in an unexpected
state. Navigation Bar subview tree might get corrupted.
Just add the code files into your project and makes your navigation controller as a subclass of APBaseNavigationController, and you'll be good to do.
Just to complete the list, here is another reason which can cause "nested push animation can result in corrupted navigation bar":
I did setup several NavigationController within a TabBarController and set
the selectedIndex within the storyboard Identifiy Properties. After moving active Tab to Code error disappeared.

UIViewController: viewWillAppear is called, viewDidAppear not

In a UIViewController subclass, I have the following methods:
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// do something
myTextField.text = #"Default";
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// do something
[myTextField selectAll:self];
[myTextField becomeFirstResponder];
}
- (void)viewDidLoad {
[super viewDidLoad];
// do something
myTextField.delegate = self;
}
The NIB has been created using Interface Builder. The corresponding view controller object is pushed by the navigation controller through pushViewController.
The inteded behavior is to show a default text entry in a text field, to select the entire text and to set the text field as first responder. [Edit: I've noticed that selecting all and making first responder makes no sense as the selection would dissapear; still, I wonder why the methods behave as described next.]
However, while methods viewDidLoad and viewWillAppear are called, the method viewDidAppear is not called. Can anybody tell me why? Most questions I found on the web and here deal with both viewWillAppear/viewDidAppear are not working; I also understood that in subviews or programmatically created views these methods are not evoked; but this does not apply in case and also I wonder why one of these "lifecycle" methods is evoked and the other not.
Any idea? Thanks!
I had this issue happen to me: viewWillAppear was being called but viewDidAppear was not!
I finally figured out that this was because I had a tabBarController where I overloaded it's own viewDidAppear and forgot the [super viewDidAppear:animated];
It threw off every VC in every tab! adding that line back in fixed it for my other VC's.
Hope this helps someone!
There is one case when viewWillAppear will be called but viewDidAppear will not.
Suppose you have two viewControllers and you push from the first to the second controller. Then, using the swipe, you want to go back to the first one, both controllers are displayed at the same time and at that moment viewWillAppear will be called from the first controller.
This way, you do not finish the swipe and stay on the second controller and viewDidAppear will not be called from the first controller.
I had the same problem.
I had copy/pasted viewDidAppear to create viewWillAppear but had forgotten to change the super.viewDidAppear() call. This then seemed to stop viewDidAppear from being called.
It sounds like somewhere in your code you have missed or messed-up a call to the superclass.
The call to viewDidAppear: should always follow viewWillAppear: unless you are doing something custom, which you say you don't. I don't know why it doesn't work but here are a few ideas:
Could it be that you are doing something strange in one of the delegate methods for UITextFieldDelegate? It's unlikely that it would affect viewDidAppear: being called but it could be a culprit.
Have you loaded a lot of stuff into memory before pushing the view? I'm not sure what would happen if you got a memory warning between viewWillAppear: and viewDidAppear:.
Have you tried to do a Clean? Sometimes that can help.
In cases like these when it should work I usually create a new class and the introduce the functionality one at a the time to see if I can get it work that way. I tried your code in a new Navigation Based project where I added a new UIViewController with an outlet to the text field. Then I pasted the code from the question and it did work as expected.
This can be because you added a child view controller to your parent VC in viewDidLoad or viewWillAppear. The child's appearance prevents the call to viewDidAppear.
This is a crazy thing to do, and I only know because this was a bug in my code. I meant to add the child VC to this VC, not the parent VC.

Getting "Using two-stage rotation animation" warning with UIImagePickerController

I wrote simple code to test UIImagePickerController:
#implementation ProfileEditViewController
- (void)viewDidLoad {
[super viewDidLoad];
photoTaker_ = [[UIImagePickerController alloc] init];
photoTaker_.delegate = self;
photoTaker_.sourceType = UIImagePickerControllerSourceTypeCamera;
photoTaker_.showsCameraControls = NO;
}
- (void)viewDidAppear: (BOOL)animated {
[self presentModalViewController: photoTaker_ animated: NO];
}
#end
And I'm getting strange warnings like the following:
2010-05-20 17:53:13.838 TestProj[2814:307] Using two-stage rotation animation. To use the smoother single-stage animation, this application must remove two-stage method implementations.
2010-05-20 17:53:13.849 TestProj[2814:307] Using two-stage rotation animation is not supported when rotating more than one view controller or view controllers not the window delegate
Got any idea what this is about? Thanks a lot in advance!
This message will appear if you are presenting the UIImagePickerController within another UIViewController. Because it isn't pushed like a UINavigationController stack, there is confusion at the UIWindow level. I don't know if the warning is a problem, but to eliminate the warning you can do the following:
// self = a UIViewController
//
- (void) showCamera
{
cameraView = [[UIImagePickerController alloc] init];
[[[UIApplication sharedApplication] keyWindow] setRootViewController:cameraView];
[self presentModalViewController:cameraView animated:NO];
}
- (void) removeCamera
{
[[[UIApplication sharedApplication] keyWindow] setRootViewController:self];
[self dismissModalViewControllerAnimated:NO];
[cameraView release];
}
Perhaps you are adding the root UIViewController's view as a subview of the window instead of assigning the view controller to the window's rootController property?
IT ALL FALLS BACK ON THE UI
This warning can be implemented for several different objects: Pickers, keyboard, etc.
I have found that it is related to the UI taking two steps to complete a transition or other animation. Or for any instance where the UI is trying to finish one thing and is being asked to execute another before it has finished. (therefore it covers a wide range of possible triggers)
I have seen the warning appear on 4.0 & 4.2. In my case I was working with rotating the device and catching whether the keyboard was still up-(i.e. text field was still first responder). If so, the keyboard needed to stay up for between the views, but this presented other complications with other views.
Therefore, I implemented a BOOL tracker to keep track if keybaordIsPresent, and if so I was {textfield resignFirstResponder]; when detecting the orientation change and the reset the textfield to becomeFristResponder after the transition that was wrapped in an Animation Block. My BOOL tracker worked better, I still use the NSNotifications for the Keyboard, but there were overlaps of notifications during rotations because the keyboard was being dismissed without requesting such. The BOOL is set to NO on Load, and when the [textfield resignFirstResponder]; is implemented. *not when "-(void)keyboardWillhide is trigger by the NSNotifications, which gives me both working triggers that never conflict. The BOOL is set to YES, only when the user touches textfield which automatically triggers becomeFirstResponder.
I removed the warning by taking the [textfild resignFirstResponder]; out of the
-(void)willAnimateFirstHalfOfRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
//if (keyboardIsPresent == YES) {[self.entryTextField resignFirstResponder];}
}
and placing it back at the top of the code for the:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
if (keyboardIsPresent == YES) {
[self.entryTextField resignFirstResponder];
}
//Determine Which Orientation is Present:
if((fromInterfaceOrientation == UIInterfaceOrientationPortrait) || (fromInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)){
//LANDSCAPE VIEW:
[self configureLandscapeView];
}else {
//PORTRAIT VIEW:
[self configurePortraitView];
}
}
**Even though I had no code inside the -(void)willAnimatFirstHalfOfRotationToInterface:, the warning was still popping up. I think the warning was still popping up because the compiler still has to attempt the method while it is trying to execute the first animation and therefore gets the double animation call or overlap of resources. It doesn't know that there is no executable code with the method until after it runs through it. And by that time it already set aside resource in preparation for handling possible actions within the method.
**To ellimiate the warning I had to remove or nil out the code for the willAnimateFirstHalfOfRotation, so that the compiler does not have to even check to see if there is a possible 2nd animation or action that may need to be executed at the same time.
/*-(void)willAnimateFirstHalfOfRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
//if (keyboardIsPresent == YES) {[self.entryTextField resignFirstResponder];}}*/
After the transition is completed, within the original animation block I check to see if the "keyboardIsPresent" was YES prior to the rotation, and if so, I resign the First Responder once again. I use setAnimationDuration:0.3which comes out pretty clean and not jumpy.
Well, you are presenting UIImagePickerController modally inside viewDidAppear of ProfileEditViewController.
Think about this. That means when ProfileEditViewController view appears, the UIImagePickerController appears, say later you dismiss UIImagePickerController and it goes back to ProfileEditViewController, then viewDidAppear is called again and UIImagePickerController appears, say later you dismiss UIImagePickerController and it goes back to ProfileEditViewController, then viewDidAppear is called again and.... you get the idea.
That warning is rather cryptic though, not sure if that is what it's trying to tell you. I would suggest making a button somewhere on the ProfileEditViewController that calls presentModalViewController and also make sure you have a way to dismiss the UIImagePickerController (I've never used it not sure if it has one automatically).
You may be trying to present two modal view controllers at the same time, and they are fighting for animation resources.
1) There is rarely any UI reason to do this. You could instead just go directly to the second view controller (the image picker); and, after dismissing it, then present the first view or view controller.
2) If you do want two stacked view controllers or a view controller on top of a view, then set a timer in viewDidAppear to present the second view controller after the first one has finished it's animation. (You could display a dummy png image of a blank picker in the first one to prevent too much display flashing until the second view controller goes live.)
EDIT - Added a random code example:
I might try substituting this as an experiment:
- (void)foo {
[self presentModalViewController: photoTaker_ animated: NO];
}
- (void)viewDidAppear: (BOOL)animated {
NSTimer *bar = [ NSTimer scheduledTimerWithTimeInterval: (2.0f)
target: self
selector: #selector(foo)
userInfo: nil
repeats:NO ];
}
A shorter time delay may work as well.
I just had the same problem. In my case was a silly mistake that I'm putting here just in case anyone else falls into that same issue.
In my tabbed app I remove one of the original ViewControllers and added a new one with Storyboard to create a "Settings" section.
This new VC had to be a table view VC and even I designed, compiled and run it without a problem, when I changed the orientation of the app I kept getting this “Using two-stage rotation animation” error.
My problem was that I forgot to change in the original .h file interface "UIViewController" for "UITableViewController".
Once this was done I changed on the Storyboard identity badge the class from the general value to my SettingsViewController and that was the end of it.
I hope it can help someone else. It took me a while to get to bottom of this.
Cheers,
I think the warning here is about Core Animation performance. As a test, I loaded the image picker without any action sheet or other animations going on and the warnings are still there. I think these are warnings coming from the image picker class itself and not from any misuse of the API.