I have a login screen(embeded in navigation controller) with 2 buttons: "Register" & "Login".
When the user press register and has successfully registered I want to to load the Login controller.
What I have in mind:
1) Draw a segue from RegisterVC to LoginVC and by pass the rootVC. This is not seems right to me
2)Save a property in NSDefaults then poptoNVC from register and have the viewWillAppear to check if it will executed the segue to LoginVC automatically.This is also does not seems to me right.
Is there any way to get a pointer to rootVC from RegisterVC executed the poptoNVC and as soon as poptoNVC is finished use the pointer to execute a segue to login?
Do you have any suggestions?
I suggest you to open the register view controller with
presentViewController (or use segue) type modal instead push the viewController.
When you dismiss the registerViewController, use:
[self dismissViewControllerAnimated:YES completion:^{
[_delegate goToLogin];
}];
so basically you can use the delegation pattern to say to the rootViewController (that is the delegate) that the registerViewController is dismissed and can access to the loginViewController.
OR: You can use your check in viewWillAppear but is not elegant for me.
Related
I am working with Parse, and one thing I have implemented in my app is their built in PFLogInViewController. This controller will be presented at two times in the application - when the app first starts and the user is not logged in, and when the user taps the "Log out" button of my application (logging out takes them back to the PFLogInViewController, as you are required to sign in to use the app). I would like to set this up using Storyboard, as that is how the rest of my app is laid out. How could I set up a central view controller (a PFLogInViewController) that is accessed at these two times? I have already Subclassed PFLogInViewController and set it up, I just need advice on how to place it in Storyboard and how to connect it to my views. To make this question help as many people as possible, the general theme of my question is how does one establish a central Login/ViewController that can be accessed at different points in the application using Storyboard. Attached is the basic idea of what I'm trying to accomplish. I haven't been able to successfully segue to the initial TabBarController, and I'm not sure how I should make the LoginController the initial ViewController if I can't segue. I am programming in Swift, if it matters.
There are a few ways to do this depending upon your application. One way is drop a UIViewController onto the storyboard, but don't wire it up to anything (no segue). Create a storyboard id for it such as "MyLoginVC". Do the necessary subclassing of UIViewController and attach the class to your VC. Then, when you want to display the VC simply do the following or wire this up to your logout button
id destinationVC = [self.storyboard instantiateViewControllerWithIdentifier:#"MyLoginVC"];
[self.navigationController pushViewController:destinationVC animated:YES];
In addition, if you want to show the login VC as the very first VC when you launch your app, then perhaps in your AppDelegate
// Load Root view controller
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
self.rootVC = [storyboard instantiateInitialViewController];
self.window.rootViewController = _rootVC;
[self.window makeKeyAndVisible];
// Load Login view controller
id initialVC = [storyboard instantiateViewControllerWithIdentifier:#"MyLoginVC"];
[initialVC setModalPresentationStyle:UIModalPresentationFullScreen];
[_rootVC presentModalViewController:initialVC animated:NO];
When you finish with your login VC (i.e. successful login) then within login VC
[self dismissViewControllerAnimated:NO completion:nil];
and alternatively instantiate your first VC with something similar to the following from within login VC. Note, since you loaded the root VC above first, it is already there with the login VC sitting over it. When you dismiss login VC, the underlying root VC should be ready to rock and roll. Otherwise you can do the following:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
RootTabBarController *tbController = (RootTabBarController *)[self.storyboard instantiateViewControllerWithIdentifier:#"rootTabBarController"];
[self presentViewController:tbController animated:YES completion:NULL];
}
I think what you want is an unwind segue. Here are the instructions I follow for an unwind segue: https://github.com/bradley/iOSUnwindSegueProgramatically
If the link dies, here is what it said:
In your storyboard create two view controllers.
Subclass UIViewController twice, once for each of the view controllers in your storyboard.
Connect these view controllers to the view controllers in your storyboard.
Make a segue between the first view controller and the second by control+dragging from the first to the second.
Click on the segue you created and give it an identifier in the attributes inspector.
Make a button on the first view controller and link it to an IBAction in its UIViewController subclass.
When this button is pressed, the second storyboard should appear. To make this happen (we are doing it programatically) put the following into the implementation of the action you just created:
[self performSegueWithIdentifier:#"nameOfTheSegueBetweenOneAndTwo" sender:self];
Create a second method in the implemention of the first view controller with the following:
- (IBAction)returnToStepOne:(UIStoryboardSegue *)segue {
NSLog(#"And now we are back.");
}
This method will work to unwind any view controller back to this view controller. Notice that we implement the method in the view controller we wish to return to.
Go back to the storyboard. Focus in on the second view controller. If it is active, you should see a dark bar beneath it with 3 symbols on it. One of these is orange and when hovered over will show the name of the UIViewController subclass that this view controller represents. Control drag from this symbol woth the green symbol that means 'Exit'. You should see all available segue unwinds, which XCode automatically enumerates when you create segue unwind implementations inside UIViewController subclasses that you have shown on your stroryboard. Hence, you should see the segue 'returnToStepOne' as an option. Select it.
In your storyboard's document outline, find the section for the second view controller. You should see an item listed below it with a grey symbol that says something like "Unwind segue from ... to Exit." Click on this item.
Important and easily missed step follows!
On the right side of your storyboard, in the attributes inspector, you should see two fields. One for 'Identifier' and one for 'Action'. In most cases, the 'Action' field will have the text 'returnToStepOne:', which is what we want, but the 'Identifier' field will be blank. Fill this field with the text: 'returnToStepOne' (note that we leave out the colon).
Create a button on the second view controller and link it to an IBAction in its UIViewController subclass.
In the implementation for the method you just created, put the following code:
[self performSegueWithIdentifier:#"returnToStepOne" sender:self];
Run the application. You should now be able to unwind from the second view controller to the first.
I have a storyboard segue with an identifier that is 'Push to ResumeView'.
I try calling it in the ViewController that I'm in at the point, by doing
[self performSegueWithIdentifier: #"Push to ResumeView" sender: self];.
But nothing happens?
I'd much rather just push the ViewController using the top NavigationController or something, but I can't see how to do that either.
Try implementing the shouldPerformSegueWithIdentifier:sender: or prepareForSegue:sender: methods in the 'from' view controller. Put a break point or NSLog() inside the method to inspect the segue identifier. This will prove that you indeed set up the segue correctly in the storyboard.
If you want to manually push your next view controller to the top of the navigation controller, use pushViewController:animated:. However, if you are using storyboard, the preferred way is to use segues.
Try this one.
UIViewController *yourResumeView=[self.storyboard instantiateViewControllerWithIdentifier:#"PushToResumeView"];
[self.navigationController pushViewController:yourResumeView animated:YES];
I have an IBOutlet on a button that will be used as a login button. It gets sent to a function for that button and I want to do my processing in there and once completed push the viewcontroller forward.
I have the login button linked already to the view controller to move forward. How do I pause that push segue from moving forward until the application does its processing and than tells it to move forward?
Instead of linking the button directly to the next view controller, create a general segue from the one UIViewController to the next UIViewController and specify an identifier for that segue, so that within the .m of you view controller, you can use performSegueWithIdentifier: when you're ready to perform the segue.
To connect the view controllers in this way, click on the black bar below the first UIViewController and control + drag from the yellow button to the second UIViewController.
Then to perform the segue use:
[self performSegueWithIdentifier:#"TheViewControllerIdentifier" sender:self];
within your button's IBAction method if the condition is met.
Do not link directly the button on the storyboard to the next viewController, link it to an IBAction instead, where you put your login code and when login is done you push the next viewController like this
[self.navigationController pushViewController:theNewViewController];
If you donĀ“t know how to create the newViewController try:
MyViewController newViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"theIdentifier"]
And don't forget to add theIdentifier to the new viewController in the storyboard
You can use the following method in your controller
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
In this method you can do your custom processing and indicate if you want the segue to be performed or not
I'm spending a lot time reading apple View Controller Programming but still can't get a clue of how to code for my flow.
I'm using ViewController, PageViewController, and Storyboard.
My rootViewController is a ViewController
I want two more ViewController
first, PageViewController to show pages of tutorials and last page has signup with presentViewController login
secondViewController, ViewController is the main content of the app
if case user has token in keychain will go to secondViewController.
After signup or login lead to secondViewController.
I didn't use navigation controller. Wonder this can be done by container view controller?
current problem In signupViewController self.parentViewController is pageViewController but I can't get the rootViewController, to dismiss and add secondViewController
P/S but In loginViewController self.presentingViewController I got the rootViewController!! it is out of my expectation.. I wonder why???
Set secondViewController as your rootViewController of UIWindow in AppDelegate. SecondViewController contains the base view content without data about login, so you can launch as soon as you can.
If user has token in keychain, just to update SecondViewController view with login status.
If user has no token in keychain, show PageViewController on SecondViewController, with presenting a viewController or just addSubview. After PageViewController, present loginViewController, when login finish, dismiss the loginViewController, update SecondViewController view with login status which is same with step2
You use storyboard, so I assume you'll also use segue. Your PageViewController can be the entry point, with a segue to secondViewController.
If you have the token in the keychain, you can programatically perform the segue using:
[self performSegueWithIdentifier: #"MySegue" sender: self];
Otherwise users stay on PageViewController to serve its original flow.
In the past my app has had only 1 main view controller (MainViewController) and a login view controller (LoginViewController) but now I am moving to a Tab Bar Controller.
Before I was able to do a simple check viewDidLoad of MainViewController for the existence of a username and password in the key chain. If a username and password was not present I used a segue to pop up a modal login view controller.
With the new setup of using a Tab Bar Controller I still only have 1 view controller (MainViewController) which is the root view controller (as of now) and I am trying to do the same thing where it pops up modal of the login screen.
Now when I call the segue in the viewDidLoad of MainViewController:
[self performSegueWithIdentifier:#"loadLoginView" sender:nil];
I am getting this error:
Warning: Attempt to present <LoginViewController: 0x1757cd80> on <UITabBarController: 0x17571e50> whose view is not in the window hierarchy!
But if I associate a button to a method that loads the LoginViewController by way of a segue it works fine. I am doing that in the MainViewController like this:
-(void)loadLogin
{
[self performSegueWithIdentifier:#"loadLoginView" sender:nil];
}
I can see from the error message that when I try to perform the segue from the viewDidLoad of MainViewController it's trying to load the LoginViewController from UITabBarController.
Why can I not load the LoginViewController from the viewDidLoad of MainViewController?
Any help with this would be great.
Thanks!
It looks like -viewDidLoad is getting called before your view controller stack is added to the window. Two things you could try are:
Delaying until the next time through the run loop (this should give the view controllers time to get in place) [self performSelector:#selector(loadLogin) withObject:self afterDelay:0];. This method won't allow you to call a method with two arguments directly
You could use -presentViewController: animated: completion:. This will cause your login controller to slide in from the bottom.