CollectionView -> changing flow based on if logged in - ios

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.

Related

Hide Login Page from ViewController

I am trying to add logic in the code to hide the login page if user is already logged in.
if (loggedin)
{
Push to MainViewController
}
else
{
Show LoginViewController
}
I know you can do this in AppDelegate, but I am hoping to add this logic in the LoginViewController.
Currently, my logic in the ViewController shows the login page for a second then push to the main page. Are there any ways to not see the login page completely?
i don't know if it exactly matches your needs but in one app i do the opposite:
i check in a viewController (the main page) if the user is logged and if it's not i show up the login page like this in the viewDidLoad method:
[self performSelector:#selector(showFirstTimeLogin) withObject:nil afterDelay:0.0];
I put it in the viewDidLoad so you don't see the "home view controller".
I hope it can help!
You Can check this in App Delegate
In application didFinishLaunchingWithOptions add this
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *viewController;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if([defaults objectForKey:#"email"]!=nil&&[defaults objectForKey:#"password"]!=nil)
{
viewController = [storyboard instantiateViewControllerWithIdentifier:#"RevealVC"];
}
else
{
viewController = [storyboard instantiateViewControllerWithIdentifier:#"ViewController"];
}
self.window.rootViewController=viewController;
try to add this logic in viewdidload even before calling its super it may work but i can't make sure of that.
you can try a better trick by adding black view controller that you handle this logic at if he is logged in go to the main screen if not show the login screen and while checking that the use will have a black screen thinking the app is loading it will be there for second
and also having this logic is App delegate is not good behaviour from software design point of view
hope this answer will help good luck :)
Here is what I do...instead of starting the user on a login or logged in page, I start them on what I always name a "RouterViewController", I run through the logic needed to figure out where the user should be "routed" and use this librar: https://github.com/callumboddy/CBZSplashView to display a nice little animation so that to the user its actually a smooth process.

Navigation to previous scene on iOS 8

I am working on an iOS 8 application that requires authentication to a backend. I would like to make the app in such a way that, if the app receives an HTTP 403 error, the user is presented with a login screen. After the login screen view controller successfully authenticates the user, the app should navigate back to the previous screen (whatever screen it was).
In Xcode 6, I can see that the preferred way to navigate between scenes is via segues. As such, I am using segues to navigate back from the login screen, with this code:
[self performSegueWithIdentifier:#"UnwindToNewsfeed" sender:self];
The problem that this presents is, I would have to establish segues to all scenes within the app, as any of them might trigger an authentication request. Therefore, I would like to ask for a recommended approach to implement this navigation requirement.
I'm new to iOS8 and to iPhone programming in general, so it could be that I don't have iOS 8's navigation concepts entirely clear and I'm using a wrong approach.
Unwind segues are different to forward segues and this makes it quite simple to support the functionality you are after.
Prior to creating an unwind segue you need to add a method to the view controller that you want to unwind to. For example -
- (IBAction)unwindFromLogin:(UIStoryboardSegue*)sender {
}
You can then create an unwind segue by ctrl-dragging between an object in your scene (or the UIViewController object for your scene if you want to trigger the unwind with performSegueWithIdentifier) and the exit icon at the bottom of the screen. Interface Builder will then display the list of methods it found that match the signature above (so it will display unwindFromLogin:). You can give this segue an identifier so that you can invoke it with performSegueWithIdentifier as you would normally do. So far so good.
Now, for the clever bit. At runtime when the unwind segue is invoked, iOS looks through the current view controller stack to find the first view controller that implements the nominated method - so if you implement the same unwindFromLogin: method in each of your view controllers, your login view will unwind to the view controller it came from and you only need a single unwind segue in your login view controller scene.
Apple has a good Tech Note that describes the unwind process in more detail and how you can customise it by implementing additional methods in your UIViewController subclass, but the default implementation should suit your needs.
If you don't want to create a segue from each source view controller to the login view controller you can present it directly using something like -
LoginViewController *loginVC=(LoginViewController *)[self.storyboard instantiateViewControllerWithIdentifier:#"loginVC"];
[self presentViewController:loginVC animated:YES completion:nil];
You can still use the unwind segue to get back
I don't think using segues is always the best approach. In a case like this, it might be better to use -popToViewController:animated:.
That said, using an unwind can still work here. I would recommend creating a custom view controller that subclasses UIViewController. This view controller implements your -unwindXXX: method.
#interface MYBaseViewController : UIViewController
- (IBAction)unwindXXX:(UIStoryboardSegue *)sender;
…
#end
Have all the view controllers which can be unwound to from the login view controller inherit this custom view controller.
#interface MYNewsFeedViewController : MYBaseViewController
…
#end
I consider the two answers below to be valid, and I voted them both up.
However, after testing, I found this approach to be simpler and less cumbersome to my scenario.
On any screen that can trigger a login prompt, I force the login screen to be presented by calling the following method:
LoginViewController *loginView = [self.storyboard instantiateViewControllerWithIdentifier:#"LoginView"];
[self presentViewController:loginView animated:YES completion:nil];
Then, in order to enable the back navigation functionality required after the user successfully authenticates in the login screen, the login screen calls this method, which returns to the previews scene:
[self dismissViewControllerAnimated:YES completion:nil];
As I am new to iOS dev, I am not sure if this is following recommended practices, so I'd like people to comment on whether this is a recommended approach or not.

Perform segue in viewWillAppear cause problems in iOS 7

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.

Circular application flow - Need Idea

I have an screen (My Profile) which can be accessed from two paths:
Login -> Content -> Profile
Login -> Register -> Profile.
In both paths, view's are shown with:
[self.navigationController pushViewController...];
But my problem is, after the user registers and completes his profile, it should go "Back" to the Content view. (Obviously it won't work with navigation controller stack, since Content isn't in the navigation controller).
My question is, what suggestions do you have?
PS: I know this isn't an actual question, but I've been thinking about this for a few hours now and I didn't come up with anything. Maybe some of you have had to deal with similar cases.
Edit: Basically the question can be generalised to:
How do you deal with a circular application flow?
Edit: I've solved this by pushing from Register to Content and then Profile in viewWillAppeare without animation (so what I need is in the stack), but I'm still interested in dealing with circular application flows.
My suggestion would by to change [UINavigationController viewControllers].
So after you end your registration you can do something like
ContentVC *content = [[ContentVC alloc] init];
[self.navigationController setViewControllers:[NSArray arrayWithObject:content]];
[self.navigationController popToRootViewControllerAnimated:YES];
Push Contentview controller after profile complated in second case , while in first case you have already pushing it.
1)Make your Login viewController the rootController of the a UINavigationController.
2)From Login you can Push Content ViewController
3)From Content VC you can push to Profile VC.
Now if you want to get back to Content from profile do this:
[self.navigationController popViewControllerAnimated:YES];
And if you want o get back from Profile directly to Login do this:
[self.navigationController popToRootViewControllerAnimated:YES];
If you do not want the navigation bar you can hide the bar.
Update
Take a different approach, other than the navigation controller stack:
1) Make a controller class with a 2 functions:
-(void)loadViewControllerWithIndex:(int)index;
and
-(void)unLoadCurentViewController;
2) You can call these functions and load and unload the view controllers from a this controller class.
3) So you initially load this class and import file in this class of other view controllers. You can take a UIViewController object topViewController, so that you can you can keep a track on which controller is currently displayed and it will help when you want to unload a controller.
4) In load controller with Index function you can add the controller view and in unload you may remove them.

Keep text in text field persistent, even when switching view controllers

I would like to be able keep the text in a textfield persistent as I switch between view controllers.
I'm making a login screen and the login. However, if I go back to the login view controller after being in another view controller, the login information disappears (I'm pretty sure it's because it's a new instance of the view controller).
What I want to happen is that if a user enters in their login information and then goes back to the login view controller, they don't have to retype their info in.
Edit: Here is code for my programmatic segue to switch view controllers:
SecondViewController *secondViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"secondViewController"];
secondViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:secondViewController animated:YES completion:nil];
NSLog(#"Login SUCCESS");
Embed your first controller in a navigation bar. Next take out that code and use:
SecondViewController *secondViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"secondViewController"];
[self.navigationController pushViewController:secondViewController animated:YES];
If you want this to persist across launches of the program, then you should store the login information whenever they change it, and then read it back in whenever your login view controller loads and set the text field values from that.
You can store the information in a couple of different ways:
iOS Keychain
See this SO question for an example of how to store information securely in the keychain:
iOS: How to store username/password within an app?
NSUserDefaults
If you are only storing the username (and not the password) then you could use NSUserDefaults.
See this question for a good example:
Save string to the NSUserDefaults?
If the login controller is the first controller, the window's root view controller, it won't be deallocated unless you change which controller is the root. This doesn't happen when you're presenting and dismissing modal view controllers. I'm guessing that you're going from SecondViewController "back" to login controller by doing another modal presentation. Is that what you're doing? If so, that's wrong, that does create a new instance of login controller as you suspected. Instead, you should dismiss SecondViewController when you want to go back to the login controller. You need to do this in code rather than using a segue in the storyboard.

Resources