Redirect to a specific view controller - ios

Just Have an issue and a "miss" in my programming "capacity".
I've got a tableview controller with some data parsed from a json.
When you choose a "news" you to to the detail view with all data in it.
Everything is ok, but I add a "check" If you are logged or not.
And if not you are "redirected" to login screen.
I try to do it with a segue (modal). It's working, but when I do it, my "navigation" is broken, like if he "lost" he's path.
I try to do it programatically like :
LoginViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"LoginViewController"];
[self.navigationController pushViewController:controller animated:YES];
But when I'm doing it like that, nothing happen, my "detail view controller" load without redirecting
and got that log:
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.
Did someone have a hint for me ?
Thanks

you are doing it all wrong. you need to study the very basic of seque programming (storyboard).
follow this link
LoginViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"LoginViewController"];
[self.navigationController pushViewController:controller animated:YES];
in storyboard you already have a push segue, & again you are pushing loginviewcontroller. thats why you are getting "nested push animation" warning.

This isn't the normal way to do it. You would normally present that login view controller modally.
If this is just the way you want it you could do it using the following steps:
1) Connect your DetailViewController to your TableViewController (not from cell itself, but from that yellow icon which represents your ViewController at the bottom black bar). Choose push if you like and add the identifier to that Segue (for example, "DetailSegue")
2) Connect your LoginViewController to your TableViewController just like you connected your DetailViewController and add the identifier to that segue (for example, "LoginSegue").
Now, when the user clicks on some cell, you wish to check if session is still active, if it is you will do [self performSegueWithIdentifier:#"DetailSegue" sender:self];, and if it is not, you will do [self performSegueWithIdentifier:#"LoginSegue" sender:self];
Hope this helps, cheers.

it's pretty tough to understand what you want to do, the question isn't too clear.
If you want to link to a scene in your storyboard though, create a segue to this by ctrl + click & drag from the initial scene, then give the segue an ID (do this by clicking on the segue and using inspector to set an ID)
then in your tableview controller, where ever you are picking up your tab (assuming this is in the tableview delegate method) you can call the segue programatically
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self performSegueWithIdentifier:#"YOURSEGUEID" sender:self];
}

Related

Segue from screen with several buttons?

I am trying to write an app using UINavigationViewController. My first screen has several buttons on it, and on the click of each button, I want to segue to a UIViewController. I know that I can add a segue on each button, all pointed to the UIViewController that I want to go to, but I was wondering if it is possible to use only one segue that can be fired from each of the buttons.
If that is not possible, I was wondering if it was possible to open the second UIViewController from the first one, on button click, and provide a Back button like the UINavigationView provides. I did manage to get everything on this idea working, except for the back button. I mean I can put a standard button somewhere on the screen and go back, but I'd like the standard back button on the UINavigationView.
Phew! I'm not sure if that makes any sense.
I know that I could also use a tableview, but I'm trying to set this up with buttons.
Thanks
Edit: Thank you to everyone that answered. I now have this working. I would vote up the answers, but I don't have enough posts to do it. I appreciate the answers!
If you need to have separate action functions for each button, suggest that you segue from the main controller to the other controller and create a segue identifier (see xcode procedure below); then, use performSegueWithIdentifier from each of the button action functions. You can also take advantage of the prepareForSegue. To create the segue, control-drag from the left button in the controller in the storyboard to the controller you want to segue to and pick show.
Check the example code in swift that I did for a very similar problem in the SO reference
Linking View Controllers through button
You can embed the main controller in a navigation controller and that will give you the ability to navigate back. If you have multiple layers you can also use unwind segue.
Link each button to one single action (ex. buttonClick) in that ViewController and then perform the appropriate segue using pushViewController method on self.navigationController
-(IBAction)buttonClick:(id)sender {
if(sender.id == self.button1) {
DestinationViewController *vc = [[UIStoryboard storyboardWithName:#"Main" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:#"VC_IDENTIFIER"];
[self.navigationController pushViewController:vc animated:YES];
}
Or if you already have that 1 segue defined in storyboards you can use
[self performSegueWithIdentifier:#"SegueIdentifier" sender:self];
And use that inside the buttonClick method. Using the 1st example, or the second one as long as the segue you setup in the storyboards is a push then you should already get the back button as that is the default behavior for pushing view controllers onto the navigation stack.

avoid navigation transition error with view controller identifier

I'm using Xcode 5 with storyboards and I should do something like this:
ViewController with a Start button that launches IntermediateViewController
IntermediateViewController that does an activity and then returns the value to the ViewController.
For the passage ViewController->IntermediateViewController I've set the start button to trigger a push segue. Actions are done and this part seems ok.
Now I have to go back to ViewController passing a string I got in IntermediateViewController methods.
If I use:
ViewController *viewController=[self.navigationController.storyboard instantiateViewControllerWithIdentifier:#"viewController"];
viewController.passedString=_mystring;
[self.navigationController pushViewController:viewController animated:NO];
I get this error:
"Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted"
Is there a way to retrieve my viewController first instance through its identifier or any other solution that will lead the app back to viewController setting also its variable?
Thanks in advance
Even if it's not the exact answer to the question, I solved using this steps:
1) checked in storyboards that each element triggers only one action or segue, not both.
2) calling second view using:
[self.navigationController pushViewController:intermediateViewController animated:NO];
2) going back to previous view.
[self.navigationController popViewControllerAnimated:YES];
3) doing this before popping:
pass string between controllers

Creating a central log out view controller in storyboard

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.

Moving from one view to another iOS

I'm relatively new to iOS development. I am to move from one viewController to another I use a modal segue transition on button click. This is a game so i want to allow the user to click images to essential move the the app menus.
I have a main page that displays several images, on clicking one i want to be able to move to another view. Currently doing this with a modal segue is causing odd problems with my touchesEnded event where if, for example, i navigate to a page 3 times the touchesEnded event is fired 3 times.
Is there a better way for me to do this or am i just missing thing fundamental?
Thanks
Yes, I think you must make the the navigation controller your root view controller then push views accordingly
UINavigationController * nav = [[UINavigationController alloc] initWithRootViewController:YOUR_BASE_CONTROLLER]
self.rootViewController = nav;
this is in your app delegate.
Then in your action method
[self.navigationController pushViewController:secondViewController animated:YES]
Im assuming you are using the Storyboard to link VCs using segues.
Modal segues are great for simple transitions but really seem to limit what you can accomplish when they are just linked through SB. Ive found that creating an IBAction that includes the following for a VC segue will allow you to not only control your segues more efficiently but also allow you to have a clearer view of what is actually occurring during the transition.
-(IBAction)goToVc:(id)sender{
//Other code to take place during the segue here
//This will identify the Storyboard in use
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
//This will identify the View Controller to switch to
SecondViewController *vc2 = [storyboard instantiateViewControllerWithIdentifier:#"SecondViewControllerID" ];
[self presentViewController:vc2 animated:YES completion:NULL];
}
Every time you perform a modal segue, you lose the UINavigationController that you were previously using. What you need to do is embed a UINavigationController in the view that you are performing a modal segue to.
Check out a question I answered the other day to help you visualize more clearly what I'm talking about.

Unrecognized selector sent to instance when calling back button programmatically

I'm viewing a detail view when clicking on a record from the table. When I call the back button from the detail view using
- (IBAction)loadDispensary
{
[self.navigationController popViewControllerAnimated:YES];
}
I get the unrecognized selector error.
I've tried pushing the the detail controller the following two ways.
Push type 1
detailViewController *detailView = [[self storyboard] instantiateViewControllerWithIdentifier:#"detailView"];
detailView.strain = self.selectedStrain;
[self.navigationController pushViewController:detailView animated:YES];
Push type 2
[self performSegueWithIdentifier: #"detailSegue" sender: self];
//Set the strain on the prepareForSegue
how the button is connected? can u show the code? perhaps you might have not properly linked the button to the IBAction.
I think you may be trying to pop a view controller that is already popped. If you have a UINavigationController and you "Push" a view controller through a segue, the back button that is displayed at the top left of the screen is already configured. You should not have to put one there yourself. If you programmitically place a button in the left bar button position it will display in place of the UINavigation's button.
Try removing the button and allowing the UINavigationController to manage going back and see if that works better.
Someone had asked me to paste the full error code and when I went to do that I saw that the method the button was pointed to was no longer there, so it was trying to call a method that didn't exist.

Resources