I've been trying to change the initial view in app delegate by putting this code
if(![[NSUserDefaults standardUserDefaults] valueForKey:#"userId"]) {
LogInViewController* lvc = [[LogInViewController alloc]init];
[self.navigationController pushViewController: lvc animated:YES];
}else {
PerfilViewController *pvc = [[PerfilViewController alloc]init];
[self.navigationController pushViewController: pvc animated:YES];
}
i have swrevealviewcontroller in my storyboard as its shown beneath, the red one is the one when its not logged in and the blue one is when its logged in
Try this. Instead of having multiple arrows, have only one that points to the very first view (LogInViewController). Then, in the viewDidLoad function of LogInViewController, place your checker code. You could then have a segue from LogInViewController over to PerfilViewController that is performed if the user is logged in; otherwise, stay on LogInViewController.
viewDidLoad{
[super viewDidLoad];
if([[NSUserDefaults standardUserDefaults] valueForKey:#"userId"]){
[self performSegueWithIdentifier:#"toProfile" sender: self];
}
Related
This is a normal LoginView calling on a specific action in my app
sourceViewVontroller
if ([password length] == 0) {
loginViewController *seatView = [mainStory instantiateViewControllerWithIdentifier:#"loggingView"];
[self presentViewController:login animated:YES completion:nil];
}
it checks if user not signed in yet when he's calling this action, so it redirects him to the loginViewController, then
loginViewController
UIStoryboard *mainStory = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
DestinationViewController *Dest = [mainStory instantiateViewControllerWithIdentifier:#"destView"];
[self presentViewController:Dest animated:YES completion:nil];
it goes to the destinationView that needs a login, now my problem is how to go back (dismiss not presentmodalView) to the sourceViewController, or simply, how to remove the loginViewController from the queue on success and dismiss directly to the source?
destinationViewController
// Tried to use presentView .. but i dont need to reload sourceView, just dismiss to it !
//[self presentViewController:srcView animated:YES completion:NULL];
//This is what am doing ..
[self dismissViewControllerAnimated:NO completion:nil];
Or just let me know if there is other professional way to do this login flow
I suggest for you another way:
First in - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
You will check user login or not. If login you will set rootView to destinationViewController. If not set rootView to loginViewController
SampleCode:
UIStoryboard *mainStory = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
if (logged) {
DestinationViewController *Dest = [mainStory instantiateViewControllerWithIdentifier:#"destView"];
self.window.rootViewController = Dest;
} else {
LoginViewController *seatView = [mainStory instantiateViewControllerWithIdentifier:#"loggingView"];
self.window.rootViewController = seatView;
}
When logout you just call notification or delegate set rootViewController of window to loginViewController.
Do not use presentViewController for bringing login controller.
Complete Process :
In Singleton class. set a global property.
#property (assign)BOOL isUserLoggedIn;
When user logs in or logs out, set this variable to true or false.
Set an enum in LoginViewController.
typedef enum {
DestViewControllerOne =1,
DestViewControllerTwo
} SignInType;
In this enum, put all your view controller where you wanna put that login check.
Set a property in login view controller to hold source controller value -
#property (nonatomic, assign) NSInteger signInType;
Set up a delegate in login controller to redirect after successfull login -
#protocol SignInProtocolDelegate <NSObject>
#optional
-(void) signInSuccess:(NSInteger) signInType;
#end
Create a property with that delegate in login controller -
#property (nonatomic, assign) NSObject<SignInProtocolDelegate>* delegate;
Now before proceeding to required view controller, perform below check -
if(![[TESingleton shareData] isUserLoggedIn]){
[self funcNavigateToSignInWithAlert:YES withSignInType:proceedToDestViewControllerOne];
}
else
{
[self proceedToDestViewControllerOne];
}
-(void)funcNavigateToSignInWithAlert:(BOOL)showAlert withSignInType:(NSInteger) signIntype
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:STORYBOARDNAME bundle:nil];
LoginViewController *viewController = (LoginViewController *)[storyboard instantiateViewControllerWithIdentifier:#"LoginViewController"];
[viewController setSignInType:signIntype];
[viewController setDelegate:self];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[[SlideNavigationController sharedInstance] presentViewController:navController animated:YES completion:nil];
}
By this, it will bring login page.
Next -
After successfull login, Do this in login controller :
[self dismissViewControllerAnimated:YES completion:nil];
[[self delegate] signInSuccess:self.signInType];
Import login delegate method in source controller that we have written above -
-(void) signInSuccess:(NSInteger) signInType
{
switch (signInType)
{
case DestViewControllerOne:
[self performSelector:#selector(proceedToDestViewControllerOne) withObject:nil afterDelay:0.5];
break;
case DestViewControllerTwo:
[self performSelector:#selector(proceedToDestViewControllerTwo) withObject:nil afterDelay:0.5];
break;
default:
break;
}
}
Implement these methods in source view controller -
-(void) proceedToDestViewControllerOne
{
//Restricting navigation to signin
//Addded by vikas Jul 8,2015
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:STORYBOARDNAME bundle:nil];
DestViewcontrollerOne *objDestViewcontrollerOne = (DestViewcontrollerOne *)[storyboard instantiateViewControllerWithIdentifier:#"DestViewcontrollerOne"];
[self.navigationController objDestViewcontrollerOne animated:YES];
}
This is complete process.
Use Unwind Segues
Add a method in SourceViewController
For Swift
#IBAction func unwindToThisViewController(segue: UIStoryboardSegue) {
}
For Objective-C
- (IBAction)unwindToThisViewController:(UIStoryboardSegue *)unwindSegue {
}
You can come back to the SourceViewController in two ways.
Using Storyboard e.g when an UIButton action fires.
Using performSegueWithIdentifier in code.
Storyboard:
Control drag form an UIButton in DestinationViewController to Exit segue inSourceViewController
In Code:
Control drag form an UIButton in DestinationViewController to Exit segue inSourceViewController
Call performSegueWithIdentifier:#"ExitToSourceViewController" when need to come back to SourceViewController
In my app after pressing the login button in my loginViewController, it push to front viewController of my SWRevealViewController. In my RearViewController I have the sign out button. When I press it it should pop to the back viewController again (LoginViewController). But even though I set the button click event like this it doesnt navigate to the loginViewController.
-(void)signOutClick :(id)sender
{
[self performSelectorInBackground:#selector(moveToLoginView) withObject:nil];
}
-(void)moveToLoginView
{
[self.navigationController popToRootViewControllerAnimated:YES];
}
But when I swipe the view it gose to the back view.I want to disable that swipe feature to the back view. And I want to go to the back view when click on the sign out button in my RearViewController. How can I do that? Please help me.
Thanks
I am not sure but instead of using
[self.navigationController popToRootViewControllerAnimated:YES];
try using,
[self.navigationController popViewControllerAnimated:YES];
And to stop swipe gesture you can use code like,
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.revealViewController.panGestureRecognizer.enabled = NO;
}
You need to reset the top view controller if you want to perform these kind of actions off of a click. E.g.
get an instance of the ECSlidingViewController
ECSlidingViewController *slidingController = self.slidingViewController;
get the view controller you wish to be on the top
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [mainStoryboard instantiateViewControllerWithIdentifier:#"mainViewController"];
UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:vc];
set the topViewController property
slidingController.topViewController = nc;
[slidingController resetTopViewAnimated:NO];
I have an app where there are 5 tabs.
I have third tab as Login. Here I call LoginViewController.
What I want to do is if user is already logged in, I want to show user MyAccountViewController instead of LoginViewController.
For that I am using below.
-(void) viewDidAppear:(BOOL)animated {
if ([[[NSUserDefaults standardUserDefaults] valueForKey:#"isLoggedIn"] isEqualToString:#"yes"]) {
MyAccountViewController *secondView = [self.storyboard instantiateViewControllerWithIdentifier:#"MyAccount"];
[self.navigationController pushViewController:secondView animated:NO];
}
}
However calling in DidAppear is too late.
Also if I double tap on Login tab, it shows Login first and after some delay show MyAccount.
What I want is if I am logged in, MyAccount will be root and when not logged in Login will be root.
Any idea how to get this done?
Edit 1
I tried as below but gives BAD_EXCESS
MyAccountViewController *tabViewC22 = [self.storyboard instantiateViewControllerWithIdentifier:#"MyAccount"];
MainViewController *tabViewC0 = [self.storyboard instantiateViewControllerWithIdentifier:#"Main"];
AboutUsViewController *tabViewC1 = [self.storyboard instantiateViewControllerWithIdentifier:#"AboutUs"];
LoginViewController *tabViewC21 = [self.storyboard instantiateViewControllerWithIdentifier:#"Login"];
LocationViewController *tabViewC3 = [self.storyboard instantiateViewControllerWithIdentifier:#"Location"];
AboutUsViewController *tabViewC4 = [self.storyboard instantiateViewControllerWithIdentifier:#"AboutUs"];
if ([[[NSUserDefaults standardUserDefaults] valueForKey:#"isLoggedIn"] isEqualToString:#"yes"])
{
myViewControllers = [[NSArray alloc] initWithObjects:tabViewC0, tabViewC1, tabViewC22,tabViewC3,tabViewC4, nil];
}
else
{
myViewControllers = [[NSArray alloc] initWithObjects:tabViewC0, tabViewC1, tabViewC21,tabViewC3,tabViewC4, nil];
}
//set the view controllers for the tab bar controller
[self.tabBarController setViewControllers:myViewControllers];
Do the check while you are initializing the tab-bar view controller items
NSArray *myViewControllers = nil;
if ([[[NSUserDefaults standardUserDefaults] valueForKey:#"isLoggedIn"] isEqualToString:#"yes"])
{
myViewControllers = [[NSArray alloc] initWithObjects:
self.myAccountViewController,
self.secondViewController, nil];
}
else
{
myViewControllers = [[NSArray alloc] initWithObjects:
self.loginViewController,
self.secondViewController, nil];
}
//set the view controllers for the tab bar controller
[self.tabBarController setViewControllers:myViewControllers];
I don't think you are using it the right way however it is not that wrong, but what i found a bit out of place was pushing "MyAccountViewController" if login is found, which is obvious case meaning the user would not log out from the app so frequently.
I have logged in facebook since 4 months and till now i haven't logged out. If the user is not logged in you can push or present the login view controller instead.
So in every case MyAccount would be your third view controller but a check in viewWillAppear will rectify your problem.
Try setting [tabbarController setSelectedIndex:2];
The thing I wanted to convey was a bit lengthy so I couldn't put this in comment
Is is possible to have a UIView preloaded so that it will load faster when the user taps on button to load it? Currently I've got a library of informaiton that I'm attempting to load when the user taps a button, and for now it seems to be "ok" , but it makes the navigation to the page choppy, because of all the information in the library it's loading.
Thanks in advance!
It should be possible to split the setup of a View Controller from code that displays the view after a button is pushed. This will eliminate the lag when the button but the task to setup the view controller still need to be done sometime during execution (You can for example put it in the ViewdidAppear method so it is executed while waiting for the button to be pushed.
Take this code for example:
-(IBAction) button_pushed {
/*setup */
NewVC *vc = [[NewVC alloc] init];
vc.var1 = var1;
vc.var2 = x;
[vc setup];
/*display */
[self.navigationController pushViewController:vc animated:NO];
return;
}
You can split the code that setup the view from the code that displays the view
into :
#synthesize vc;
…..
- (NewVC) setup {
//setup
NewVC *vc1 = [[NewVC alloc] init];
vc.var1 = var1;
vc.var2 = x;
[vc setup];
return(vc1);
}
-(void) ViewDidAppear {
if (setupready) {
vc = [self setup];}
return;
}
-(IBAction) button_pushed:(ID) sender {
//display
[self.navigationController pushViewController:vc animated:NO];
return;
}
I'm confused. I have a navigation controller with a BarItem which opens a first view. After some work is done, I want this view to disappear and I want a second view to open.
root view: navigation controller
first view: activity indicator, where some data is put together
second view: MFMailComposeViewController
In the root view, the BarItem runs these lines to open the first view:
IndicatorViewController *indicator = [[IndicatorViewController alloc] initWithNibName:#"IndicatorViewController" bundle:nil];
indicator.view.backgroundColor = [UIColor clearColor];
self.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentModalViewController:indicator animated:YES];
The first view (IndicatorViewController) does some work and finally runs
[self dismissModalViewControllerAnimated:YES];
This works fine. But - how do I open the second view?
I tried this:
I open the second view. After closing the second view, my first view pops up again (since it is still there) and get's dismissed at this point. This code is placed in the first view:
- (void) viewDidAppear:(BOOL)animated {
static BOOL firstTime = YES;
if (firstTime) {
//do stuff that takes some time (that's why I show the indicator)
MailViewController *controller = [[MailViewController alloc] init];
if (controller)
[self presentModalViewController:controller animated:YES];
firstTime = NO;
} else {
[self dismissModalViewControllerAnimated:YES];
}
}
Since the first view pops up again, the user can see the indicator one more time, after the second view is closed - and that is not what I want.
What am I missing here? What would be the better way to do this?
I would do something like this. Make a navigationController, and make the first view as the root controller. Then do something like this:
FirstView.m
- (void)viewDidLoad
{
[super viewDidLoad];
[self.navigationController setNavigationBarHidden:YES];
}
- (void) nextView { // however you get to your next view, button/action/etc.
UIViewController *screen = [self.storyboard instantiateViewControllerWithIdentifier:#"yourIdentifier"];
[self.navigationController pushViewController:screen animated:YES];
}
Then in the second view:
SecondView.m
- (void) nextView { // however you get to your next view, button/action/etc.
UIViewController *screen = [self.storyboard instantiateViewControllerWithIdentifier:#"yourIdentifier"];
[self.navigationController pushViewController:screen animated:YES];
}
And finally in the rootview:
RootView.m
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *navStack = [NSArray arrayWithObject:self];
self.navigationController.viewControllers = navStack;
[self.navigationController setNavigationBarHidden:NO];
}
This will make your RootView the new rootview of the NavigationController.
self.navigationController.viewControllers
is the array with all the ViewControllers that are on the navcontrollers stack. The first object is the rootcontroller. If we replace the whole array with our own array, it knows only one item. You CAN go back by dismissing if that's what you want though. This isn't the prettiest way of doing it, but it's not the worst either.