I want the view controller to check something, and if it's true it would allow the user to use the view controller, and if it's false it would show an alert to the user and send the user back where he/she came from.
So I tried adding this to an if-statement at the end of viewDidLoad:
[self.navigationController popViewControllerAnimated:YES]
However, I got the error:
2014-08-09 20:12:59.731 ProjectName[1978:60b] nested pop animation can
result in corrupted navigation bar
2014-08-09 20:13:00.118 ProjectName[1978:60b] Finishing up a
navigation transition in an unexpected state. Navigation Bar subview
tree might get corrupted.
I learned from this StackOverflow question that calling pushViewController or popViewController before viewDidLoad finishes is unsafe. Are there any ways around this?
TLDR: I'm trying to push a view controller onto the stack, show an alert, then pop the view controller off of the stack.
EDIT: Added code.
This should be fairly easy provided you want to show the alert.
1 - Call [UIAlertView show] method from within viewDidAppear. It would be advisable to use viewDidAppear as it would be last in the view life cycle, when the view controller is fully pushed on the stack. So popping will be harmless.
2 - In clickedButtonAtIndex delegate method, call popViewControllerAnimated.
Related
From an initial ViewController I've modally presented a second ViewController using a ShowDetail segue in the storyboard and a performSegueWithIdentifier: method call. The problem is when I dismiss this modal ViewController with the method dismissViewControllerAnimated: the initial ViewController is reinstantiated calling the viewDidLoad again.
I've tried using a Push segue instead of the Show Detail and the initial ViewController keeps allocated in the background as it should.
What might be going on? The initial ViewController never even calls the memory warning method.
Have you tried unwindSegues?
***** Long explanation ahead, skip to solution if you want the quick way *****
First of all, if it is a ShowDetail, it is not a modal view. Do try to see which is your case.
Modal segues can carry information backwards, but are a bit more complicated than push ones.
If you are modally presenting it, you should use Present Modally instead of a ShowDetail.
A modal presentation will always take the top view position in the stack, and Show Detail does as well, depending in how your views are set. For instance, if you have a detail view in stack, IT will be replaced rather than the stack top view.
Try choosing up to a specific segue, I particularly recommend modal assuming you need more than simple pushes (Or the Show would have closed the problem, being the equivalent to the previous deprecated push. If you only need something simple, Show is the way)
Now we've cleared this, what probably is happening is that the view is being removes since Show Detail replaces views instead of pushing them, and it has to perform init again.
***** Solution: *****
The solution then should be not to lose the view when replacing, and reinitializing it, what dismissViewControllerAnimated: does. If you use unwind segues, though, the view should be replaced BUT retained by ARC.
The following link has the best explanation all over the net about how to use it:
What are Unwind segues for and how do you use them?
I have master view controller (derived from UINavigationController) which seques to view controller A.
When the user exits A an unwind seque returns to the master controller which then seques to view controller B.
The problem I am facing is that if I have the following code in the master view controller:
- (IBAction)unwindToMasterViewController:(UIStoryboardSegue *)segue
{
[self performSegueWithIdentifier:#"SequeToViewControllerB" sender:self];
}
Then I get the error: "nested push animation can result in corrupted navigation bar Unbalanced calls to begin/end appearance transitions for View Controller B".
However if I remove the call to the performSeque from within the unwind seque and trigger it manually from a button on the master view controller then everything is ok. Therefore this suggests the problem is timing related, and in fact I've seen similar problems like this in the past which were related to animation timing (trying to call pushViewControllerAnimated:YES before a previous call to push has totally completed etc.).
So bearing that in mind I tried putting the seque in the code below, expecting didPopItem wouldn't get called until view controller A had completed being popped off the stack.
- (void)navigationBar:(UINavigationBar *)navigationBar didPopItem:(UINavigationItem *)item
{
[self performSegueWithIdentifier:#"HomeSeque" sender:self];
}
However that didn't solve it.
So how can I tell when view controller A has finished being popped off the stack so I know its safe to seque to view controller B? (Assuming that is indeed the problem, but seems like it is due to my button experiment).
Alternatively is there a way I can get the OS to transition from VC A to VC B for me?
You can use the approach discussed here: popping and pushing view controllers in same action
In other words, instead of using the canned unwind segue, which will call popViewControllerAnimated:YES, you pop by calling popViewControllerAnimated:NO and now you can go straight on to a push segue.
An even cleaner way is to call setViewControllers:animated: with the new stack of view controllers.
Question looks crazy, but I had faced an issue, in which I want to implement like this. Consider I have a view(A) showing currently, in one case I want to pop the view and show other view e.g.(ViewB) instead of ViewA, so What I have done is I have wrote a function in ViewA class to pop like this...
[self.navigationController popViewControllerAnimated:YES];
Next to the function call I am pushing new View, now app is crashing by saying.. Nested push may corrupt your navigation controller ......
What am I doing wrong here... Can't we do pop and push immediately...How to handle this case..
thanks.
You can try presenting your views modally and dismissing it. But if you want to do this with push and pop then you can do the following:
In your View A pop the view and set some flag which can be accessed in the previous view controller (i.e the view from where View A was pushed).
Next check this flag in the previous view's viewWillAppear and push View B.
Hope this helps.
If you want pop and push immediately just set the popViewControllerAnimated:NO – Guo Luchuan
I have a modal view which is launched from the current view controller, as
[self presentModalViewCOntroller:modalViewController animated:TRUE];
The modal view controller dismisses itself when someone hits a button.
[self dismissModalViewControllerAnimated:TRUE];
A couple of screens later, I attempt to swap the root view within the window. I do this all the time with no trouble. But in a certain case, when switching the one view within the window, the picker delegate method is being called on the modal view controller even thought it was dismissed a while ago.
This is very strange because the modal view controller is usually deallocated when dismissModalViewController is called.
Why is a view from the modal view controller being invoked?
It appears that someone, probably the window still has a reference. Are you supposed to do something else in addition to dismissModalViewController?
Thanks
DismissModalViewController should be enough. It does seem like you have a problem with some reference hanging around that you don't intend. Without seeing more code, I can't point to anything specific.
I need to save my data by calling a method I already have when a viewController is popped using the back button created by the UINavigationController.
Is there a way to get a delegate callback or a notification I didn't see anything in the documentation?
In your viewWillDisappear method, you can check the property:
[self isMovingFromParentViewController]
to find out if the view is disappearing as a result of being popped off the stack or not.
You will be notified that the view will be disappearing, with the view controller method viewWillDisappear:, however, this will be called each time the view is moved offscreen, whether that means the controller is popped or a new controller is pushed, or whatever else may cause your view to disappear.
Perhaps a better design would be to save your data in your controllers dealloc method. Normally, a navigation controller is the owner of a view pushed into it's stack, so popping it usually causes it to deallocate. This isn't always the case though and depends on how you've written your app.