pop more than one views when back button is pressed? - iphone

I am developing an application in which I am using a login form at first screen. If the user is new he is takne to the signup form and after that he is also taken to the home page as a normal user.
Now my question is "If the new user presses back btn, how can I direct him back to the login page and not to the sign-up forms and all in between?"
Should I change the navigationcontroller's viewControllers array?

- (NSArray *)popToRootViewControllerAnimated:(BOOL)animated on UINavigationController will pop the user back to the last view controller in the stack.
If you want to get the navigation stack to a new known state you can use - (void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated the last item in the array will then be the active one.

UIViewController has some methods for this. You can use
- (NSArray *)popToRootViewControllerAnimated:(BOOL)animated
to pop up to the top view controller, or
- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated
to keep popping until you get to a specific controller you know is on the stack somewhere...

Perhaps you should think about your problem from another angle.
The signup form isn't really part of the flow of things--it's a temporary, one-time, mandatory interjection.
If you made the signup form a modal view, then you could just dismiss the modal view when signup is complete (or cancelled) and move normally to the next view controller.
That way, when you back up, the login view is the immediately previous one.

Related

Change initial view controller after first launch of app

I have a two-view login to my app where a user enters two views worth of info. After the user has entered that info I want change which view is the initial view controller, and have the login view be a settings-like page.
How can I change the initial view controller after the user has passed a certain point in the app?
For one of my apps, where I did similar to this, I have my "main" view controller check on viewDidLoad for a setting in the default settings that would indicate if the user had signed in. If they hadn't, I immediately pushed the loginViewController without animation and the user filled in the appropriate forms. When that was dismissed, I reloaded the view in my main view controller.
My client liked the app and it looked nice.
If the user has already "passed a certain point", then what you change to can't be "initial" view controller, can it? The "initial" view controller is the view controller shown on launch.
Do you mean that you want a different view to appear first on subsequent launches? Then write something into the NSUserDefaults that you can check on subsequent launches so that you can start with a different window.rootViewController? Like this (changing all the names) in your app delegate's applicationDidFinishLaunching:
if ([[NSUserDefaults standardDefaults] valueForKey: #"loginDone"])
self.window.rootViewController =
[[UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil]
instantiateViewControllerWithIdentifier:#"secondVC"];
Or do mean that you just want to navigate away from the login stuff and never return? Then use a presented view controller and just never dismiss it.

Trying to understand segues, memory management, and best practices

What I'm doing is creating a login screen as the first page. Once you login and it verifies you against the server it clears the login fields and it segues to a home screen. That screen has a back button that I've given the text logout. Clicking that takes you back to the login screen, and since the login button verifies you against the server before the segue it essentially looks like you're logging out.
However, I would like a logout button on each page. My thought for this was to add a button to the navigation bar of the other screens. As a test I added a logout button to a screen several levels in and added a segue back to the login screen. I updated a label on the page to see if it went back to the same page. When it segued back to the login screen the label was blank leading me to believe I didn't go back to the login screen, but rather it created a new login screen. How do I log out and have it essentially go back to the beginning?
Am I going about this the right way or is there a best practice in regards to this?
Every time to transition to a new view controller via a segue you are creating a new instance of the destination view controller. So yes, if you go back to the login screen using a segue you will be adding more view controllers to the navigation stack.
It sounds like you are using a UINavigationController. If so you can use the method popToRootViewControllerAnimated: to remove all view controllers from the navigation stack and return to the root (which is your login view controller). The other view controllers will be dealloc'ed when they are removed from the nav stack and you won't have the eventual memory problem you describe.
// do this when the user clicks your Logout button
[[self navigationController] popToRootViewControllerAnimated:NO];

iPhone SDK: Know when tab on Tab Bar is clicked?

I have a tab bar which displays different views when clicked. When you click a tab for the first time, it calls the viewDidLoad method. But, it only calls that the first time.
Is there a method that is called when a user clicks back to that tab, since the viewDidLoad won't be called that second time?
(I need to do this to update a UITableView when the user clicks back to a tab)
Of course!
- (void)tabBarController:(UITabBarController *)aTabBarController didSelectViewController:(UIViewController *)viewController
Your best option when looking for these sorts of things is to look in the documentation, specifically at the delegate for the object you're interested in.
http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UITabBarControllerDelegate_Protocol/Reference/Reference.html
I would use - (void)viewWillAppear:(BOOL)animated in UIViewController (docs)

iPhone - Returning a value from a UIViewController which is presented using presentModalViewController

I have a very simple scenario:
My iPhone application contains a UIViewController implementation which displays a list of items. In its navigation bar there is a button for adding items to that list. When this button is clicked, a new UIViewController is instantiated and presented on the screen using:
[self presentModalViewController:controller animated:YES];
This controller contains views that take user input for a new item in the list. After the user is done entering information, he clicks the "Done" button.
The "Done" button should take all entered information and return it to the first controller (the one displaying the list). The first controller could then add an item to its list based on the information that was just entered.
My question is: How do I send back the information from the second controller to the first controller in a nice fashion?
You can use protocols...In your modal view controller you can define a protocol that must be implemented by its delegate say the method -(void)userDidEnterInfo:(some sort of info), in your view controller that you want to pass the info to you can conform to the protocol and become the view controllers delegate...right before you dismiss or whenever you are r eady to send the info over you can call [delegate userDidEnterInfo:] and the view controller will receive the information...Heres more on protocols http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocProtocols.html#//apple_ref/doc/uid/TP30001163-CH15

Navigation view controller question

Below is what I want to implement:
The main screen of my app is a UITableView. Each row in the table view is a category, when you click the detail disclosure button in the row, you can see a bunch of items under this category in the category detail view.
Now in the main screen, I click the "+" button in navigation bar to create a new category. (The new category will become a new row in the table view). The app then take me to the "Add Category" view. (I used presentModalViewController)
In the "Add Category" view, I set something, then click "Save" button to dismiss the "Add Category" view. (I used dismissModalViewControllerAnimated)
Usually after I click "Save" button, the app will take me back to the main view and I will see a new row in the table.
But that's not what I want to go, what I want is - after I click the "save" button, the "Add category" view will be dismissed but not return to the main view. Instead, I will see the details of the new-created category so I can continue to add items under this category. The result is just like "I return to the main view and then click the detail disclosure button of the new-created row (category)".
Does any one know how to realize that? Thanks!
You can do this by doing a little decoupling of one screen from another:
- Create a custom delegate and protocol for your category creation modal dialog. Something simple like:
#protocol CategoryCreationProtocol
- (void) categoryAddDone:(NSString *)category;
- (void) categoryAddCancelled;
#end
...
#interface CategoryCreationDialog : UIViewController {
...
id<NSObject, CategoryCreationProtocol> categoryDelegate;
}
#property (assign) id< CategoryCreationProtocol, NSObject> categoryDelegate;
- In the modal dialog when the user taps the 'Save' button, after dismissing the view controller, you invoke the delegate method:
if (categoryDelegate && [categoryDelegate
respondsToSelector:#selector(categoryAddDone:)])
[categoryDelegate categoryAddDone:newCategory];
Also, something similar for the Cancel button.
- Your main controller implements the categoryAddDone method and sets itself to be the categoryDelegate for the modal dialog.
- At runtime, when the user taps Save the delegate method is invoked so your main view is notified that something has happened and it can push the right view into place and even jump to the proper category.
- In your case, as soon as the category creation is done, the main view controller is notified, so it can release the category creation dialog and push the category detail view into the stack. The user sees the modal dialog disappear and slides right into the detail view.
- In general, using delegate/protocols for push navcontroller and modal dialogs is a really handy pattern for making decoupled and reusable views. This way they can be invoked from a variety of places. To make it consistent, you may also want to have a show method on each modal dialogs and pushed view controllers that the caller can invoke. This way there's a consistent way to get into and a consistent way to get notified that the user is done with it.
If you use presentModalViewController and its corresponding dismissModalViewControllerAnimated, then you will return to the view controller in which you issued the initial presentModalViewController message.
Instead, you may want to push on the stack the view controller in charge of adding the new category, and when you are done, you simply push on the stack the view controller responsible for showing all of the items of that category. Thus, you should use
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated