I have a project where I have, among other screens, a History screen, a ChooseProfile screen and a Register New Profile screen.
If the user enters the History and don't have a profile selected, he must be redirect do the ChooseProfile and then return to the History with the profile. Also, in the ChooseProfile screen, if it has no profiles yet, he must be redirect to the Register New Profile screen.
The user must not see all the transitions of the screen. When he chooses to enter History, he must only see the transition to the final screen (for example, if a have no profile and click to go to History, I must see the transition to the Register New Profile, so I can fill my data and when click in OK, go back to history with a valid profile - not even seeing the ChooseProfile between).
I could achieve this, in iOS 6, by performing the segues (or making pushes) in the viewWillAppear of the controller, and everything looked fine. But in iOS 7 I'm having strange effects. For example, sometimes the screen freezes in the first controller (History) and, even if the app doesn't crash, everything seems disable.
In the debug, it seems like he is pushing the other controllers, but the screen (view) isn't changing.
Someone could help me with a solution? I don't want to rework all my flow to solve this...
Thanks.
Here some partes of the code. Hope it helps.
In the HomeController (the root):
- (IBAction)historyBtnPressed:(UIButton *)sender {
UIViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"HistoryController"];
[self.navigationController pushViewController:vc animated:NO];
}
In the History Controller:
-(void)viewWillAppear:(BOOL)animated {
[_tableView reloadData];
if(!_profile)
[self selectProfilePressed:nil];
}
- (IBAction)selectProfilePressed:(UIButton *)sender {
[self performSegueWithIdentifier:#"ProfileListSegue" sender:nil];
}
If, in the first code block, I left the animated:NO, it works fine, but I have no transition effect, even with the segue in the second controller. The screen (ProfileList) simply appears.
If I set it to animated:YES in first code block, my navigation stack seems to get messy.
Related
I'm currently working on an app that builds a stack of controllers depending on the user.
Basically, I have a UIViewController that has a UIButton leading to another UIView Controller; that has a button leading to another view controller and so on. The view controllers are pushed so that when the user always press the button, I get a stack of multiple view controllers. The views are popped whenever the user wants to go back to the previous view controller.
Everything is working well (push and pop). However, at random instances, the app would crash. I noticed that it happens when there are already a large amount of views pushed, and I suspect that it can be a memory issue.
My question is, other than pushing the view controllers, is there an alternative so that I can avoid stacked views? Could it also be that the crash is not because of the stacked views but because I'm just missing something out? There is no error presented in the logs so I can't find out what's happening and I'm also new to iOS development.
Thank you very much!
Edit 1: There is no error in the logs but when the app crashes, there is this message:
Thread 1: EXC_BAD_ACCESS(code = 1, address = 0xd000000c)
Edit 2: This is how I am pushing the controller:
CustomController *custom = [self.storyboard instantiateViewControllerWithIdentifier:#"Custom"];
[self.navigationController pushViewController:custom animated:YES];
And this is how I popped it when the back button is pressed:
[self.navigationController popViewControllerAnimated:YES];
Edit 3: After enabling zombie objects in the scheme, I started to get this messages after multiple push and pop:
nested push animation can result in corrupted navigation bar
Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.
Unbalanced calls to begin/end appearance transitions for
Do those messages say that the problem is actually on pushing the controller with animations? Thanks everyone!
Edit 4: I'll try to revise the question to make it more descriptive
This is my setup:
Controller A displays icons that corresponds to different places. You can click on the icon to push Controller B and display details for Location A.
Controller B displays information about Location A, with a button to show Controller A that now displays icons close to location of Location A. Now, you can again click an icon, say for Location B, and display details and so on.
When the user presses the back button, it should display the previous view controller. This is why I used push and pop. Is there a better way to handle this process. Thanks again!
My suggestion is: check if Zombie Objects is enabled and use the instrument "Allocations" to see if your application have, in fact, memory issues. With the informations provided by these tools, you can figure out what is happening with your application and work on it.
Tell me if you need help.
Good luck!
When push or pop, you should turn off animation. I think this causes crash when animation does not finish.
Push: self.navigationController pushViewController:custom animated:NO];
Pop: [self.navigationController popViewControllerAnimated:NO];
My guess is that you push multiple view controllers with animations - this may be a root cause of error. If you push more than one view controller you should animate only LAST push, say:
VC1 *vc1 = [self.storyboard instantiateViewControllerWithIdentifier:#"VC1"];
[self.navigationController pushViewController:vc1 animated:NO];
VC2 *vc2 = [self.storyboard instantiateViewControllerWithIdentifier:#"VC2"];
[self.navigationController pushViewController:vc1 animated:NO];
VC3 *vc3 = [self.storyboard instantiateViewControllerWithIdentifier:#"VC3"];
[self.navigationController pushViewController:vc1 animated:YES];
However, i hardly imagine the situation where the multiple push would be necessary - i think it always leads to bad UX.
I am making an iOS app where the user starts in the main menu (see figure).
When the user clicks button1, it triggers a segue (1) that takes him to a configuration wizard. On the other hand, clicking button2 takes the user to a configuration listing (showing what is already set), this also using a segue (2). Both these view controllers have a back button, that takes the user back to the main menu by calling
[self dismissViewControllerAnimated:YES completion:nil];
What I'm now struggling to implement, is a way to make the transition from the configuration wizard to the configuration listing.
When the user has made his choices in the wizard, and pushes the save button, I want this to take him directly to the configuration listing view. At the same time, the wizard view controller should be "forgotten", that is when the user now pushes the back button2, it should still take him back to the main menu. This means that I cannot just trigger a segue to the listing from the wizard, since then the wizard would still be there, "behind" the listing view, and would become visible when back button2 was pressed.
Any ideas on how to smoothly implement this?
You can add a segue from Configuration Wizard to List of Configurations. To avoid going back to Configuration Wizard store the Main Menu ViewController pointer and say popToViewController API for navigation.
Code sample where popToViewController is being used.
NSArray * controllerArray = [[self navigationController] viewControllers];
for (UIViewController *controller in controllerArray){
//Code here.. e.g. print their titles to see the array setup;
//NSLog(#"%#",controller.title);
if ([controller.title isEqual:#"ViewTitle"]) {
[self.navigationController popToViewController:controller animated:YES];
}
}
Hope this helps.
At Configuration Wizard screen, use presses save
[self.navigationController pushViewController:listOfConfigurationViewController animated:YES];
At this time, your stack is :
Main View Screen -> Configuration Wizard Screen -> List Of Configuration Screen
When uses presses back button at List Of Configuration Screen
// you will come back to Main Screen View
[self.navigationController popToRootViewControllerAnimated:YES];
I'm trying to get a storyboard to bring the user back to the first screen of a storyboard when a button is pressed.
I have the button click hooked up and the method is hit when it's tapped but it's either doing nothing or crashing the app depending on what I've got in that method (I've tried so many things at this stage that I can't remember the original setup)
The best I can achieve is that once tapped the user gets brought to the third screen in the storyboard, rather than the first.
Here's the storyboard, I want to get the user to move from the button circled in red back to the very first view controller (top left of screenshot).
Maybe the storyboard layout will help people, I'll post some of the various methods I've tried as well.
Here's the method
- (IBAction)done:(id)sender
{
//Multitude of attempts have been in here, either they don't do
//anything or they just send the user back to the NEW REPORT screen.
//Button does nothing in these following events
[self.navigationController popToRootViewControllerAnimated:YES];
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:0] animated:YES];
}
If you want to start fresh, have the button instantiate a new instance of the first controller, and set it as the window's root view controller:
FirstViewController *first = [self.storyboard instantiateViewControllerWithIdentifier:#"First"];
self.view.window.rootViewController = first;
It's not clear to me exactly how you're getting to that controller with the button in question, but you might want to put dealloc methods in all your controllers with a log to see if all are getting deallocated at some point in your navigation, and when you go back to the new first controller as I've outlined above.
I have an App using a Story Board, CollectionViews and a NavigationController setup. This works fine, but now I want to add in login.
So if the user is already logged in, I want to bypass the default behavior of going to the login screen.
What is the best way to change this flow?
thanks!
phil
Put logic in the viewDidAppear method of the navigation controller's root view controller that determines whether to show the login view or not. Present it modally with the animation set to no, and it will be the first thing the user sees.
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (!self.loggedIn) {
UIViewController *login = [self.storyboard instantiateViewControllerWithIdentifier:#"Login"];
[self presentViewController:login animated:NO completion:nil];
}
}
You can either tell the regular first view controller to instigate the segue in code when it appears (e.g. login view says: show next view if logged in).
Or something more radical in your app delegate, but I think it is safer to leave the flow as it is and just make it move on to the next screen and leave your storyboard untouched.
Simplified question: Is there any way to restart the navigationController of an application?. I'm trying to force the application to get his initial appearance.
Long explanation
I've a pet project in iOS and I have a weird problem with the interface that I'd like to solve. I'd like to understand also the mechanics behind this behavior.
I've a simple welcome view, wich shows the splash screen of the application. After that, thread goes to sleep state for 1.5 seconds.
[NSThread sleepForTimeInterval: 1.5];
Then, I'm showing an advertisement view:
AdController *ad = [[AdController alloc] initWithNibName:nil bundle:nil];
[self.navigationController presentModalViewController: ad animated:YES];
[ad release];
And that's all the logic behind. After that, other controllers are pushed without incidence. I want to achieve that, if at any moment the user makes the application go to background (pushing the iPhone/iPad button) then all the controllers must disappear from the stack via pop. In order to get it I'm using applicationDidBecomeActive event from the delegate. The code is the following:
[self.navigationController dismissModalViewControllerAnimated:NO];
[self.navigationController popToRootViewControllerAnimated:YES];
This is driving to some weird visual behaviours. Depending of the moment that the user choose to push de button the transition to the first view is visible. In other cases the ad view is still present, so it is dismissed and then appears the splash screen.
It will be great if there is some way to reset this first controller (splash screen), in order to get all the transitions working as the first time. I've thought about pop it from the navigation controller and the reload another one, allocating again, but it seems a bit complicated.
Is there any simple way to achieve that?
Important Edit: If the user forces repeatedly the application to go background then these exceptions are thrown:
nested pop animation can result in corrupted navigation bar
Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.
The easiest way that I've found is to add to the plist file a new row with key "Application does not run in background" and with value YES.
Forces the application to be completely closed and unloaded from memory when the user pushes the button.