Making a segue through button action - ios

I am trying to make a login in screen where when you press login it will check the username and password then if it is all good it will segue to the next view.
I have 1 view controller with 2 buttons just to test that I can successfully segue with a button action to another view controller. 1 button is my attempt to programmatically link the two view controllers and the other button is linked by a modal and it successfully switches between the views.
for the first button my code is,
#IBAction func testButton(sender: UIButton) {
performSegueWithIdentifier("nextView", sender: self)
}
for the storyboardID of the view controller to be switched to it is indeed 'nextView'
I get an error, 'NSInvalidArgumentException', reason: 'Receiver has no segue with identifier 'nextView'
I have cleaned up the code and also tried removing the app from the simulator.
Any suggestion on what the issue may be? Or is there a better way to make a login screen?

In order to perform segue on button tap with custom logic, select controller one (not button) control drag and drop on controller two. chose the segue and give an identifier value in storyboard. Then when you call performSegueWithIdentifier, it will work.

You need to set the identifier for the segue, not the StoryboardID of the view controller:

try this UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainstoryBoard" bundle:nil];
ViewController* viewController = [storyboard instantiateViewControllerWithIdentifier:#"StoryBoardIdentifier"];
[[self navigationController] pushViewController:viewController animated:YES];

performSegueWithIdentifier refers to the id of the segue not the storyboardID of the viewController you're trying to load. That being said, you could either create a segue between the view controller you're on to the destination view controller and use performSegueWithIdentifier, or you could create an instance of your storyboard and use its instantiateViewControllerWithIdentifier method which takes the storyboardID as a parameter. I'm posting from mobile so that might not be exact, but that should help you out.

Related

Segue 2 view controllers forward not working

I have 3 viewControllers. viewController1 is linked to viewController2 (via segue id "first"), and viewController2 is linked to viewController3 (via segue id "destinationController"). I'm trying to segue from viewController1 to viewController3. Here is my code:
UIViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"DestinationController"];
[self.navigationController pushViewController:controller animated:YES];
It crashed with the following error:
'Storyboard (<UIStoryboard: 0x7fb1a944be00>) doesn't contain a view controller with identifier 'DestinationController''
How can I segue 2 viewControllers without connecting the first to the last? (I prefer not adding a segue from the storyboard because it will get very messy.)
The error is telling you that you don't have a controller with the identifier, "DestinationController". From the text in your question, it seems that you have a segue identifier called "DestinationController", but that's a different thing from an identifier on the controller, which you set in the Identity Inspector with the "Storyboard ID" field.
I think it would be more consistent though, to make a segue from the first to the third view controller. It also makes the navigation among your controllers clearer in the storyboard.
Please check "DestinationController" segue is bind with you current ViewController in which you write this code.
If you perform segue from VC1 to VC3 there is only one way in your case you have to go through VC2 (You can place conditions on viewDidLoad method of VC2 to perform segue with VC3).
Please bind "DestinationController" to your current controller and your error will gone.
This may help you :)
UIViewController3 *controller3 = [self.storyboard instantiateViewControllerWithIdentifier:#"DestinationController"];
[self.navigationController pushViewController: controller3 animated:YES];
Don't forget the set the storyboardId "DestinationController" not the segue name, Check the below Link,
Check the answer

Redirect to new view controller in the middle of navigation stack

I am fairly new to navigation view controllers and stacks in iOS. Please help me with this, tried searching for a long time couldn't find anything relevant.
I have a LoginViewController, a SWRevealViewController for side menu operation, a FirstViewController (the first one in navigation stack) and a SecondViewController (second in navigation stack).
I have to do the following in LoginViewController, assume login and found are two boolean variables:
if (login && !found) {
//redirect to FirstViewController : the following works
[self presentViewController:swReveal animated:NO completion:nil];
}
else if (login && found) {
//redirect to SecondViewController
}
Please help me fill the else if. Really appreciate your time!
So based on what I understood from your comments, FirstViewController is a subclass of TableViewController and SecondViewController is the DetailView.
So based on that, the best approach for "redirecting" to the DetailView (SecondViewController), would be creating a segue on the Storyboard, and then calling that segue programatically once the FirstViewController is loaded (in its viewDidLoad)
On both cases you would first show the FirstViewController and then depending on the if statement, you would either stay or go to the SecondViewController.
So first step: Create the segue from the Storyboard, and give it an identifier.
Second: Perform that segue programatically when the FirstViewController is loaded (and of course, the if statement is valid) by using:
[self performSegueWithIdentifier: #"MySegue" sender: self];
More on that subject:
Alternative ways to push view controllers with storyboard programmatically
Creating a segue programmatically

IOS opening other view controller on buttonclick not working with storyboards

I am having a silly problem with opening another viewcontroller on a buttonclick.
On my viewcontroller on my storyboard, I have a button. When a users clicks on this button, a new viewcontroller should be opened. As far as I know, there are 2 ways to do this.
in code
on the storyboard itself
Both methods are not working for me.
First the problem with storyboards:
(source: livefilestore.com)
I have connected my mainViewController with a navigationController, and I have connected my button with my next view (for adding an item). However, when I run the program, I get the following error:
'NSGenericException', reason: 'Push segues can only be used when the source controller is managed by an instance of UINavigationController.'
I really don't understand this error, because the mainviewcontroller IS managed by a UINavigationController.
So, as this didn't work, I tried to handle it in code. I connected the buttonclick action to the mainViewController.h file and implemented it in the .m file.
This is the action method when a user clicks on the button:
- (IBAction)actionBtnAdd:(id)sender {
AddInventoryViewController *addinvController = [self.storyboard instantiateViewControllerWithIdentifier:#"AddInventoryViewController"];
[self presentViewController:addinvController animated:NO completion:nil];
}
The other viewcontroller is in the same storyboard, and the ID of the other viewcontroller is "AddInventoryViewController". This gives me the following error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
Anybody who know the problem? What would be the best approach to solve this?
Your navigation controller is not the initial view controller. Select your nav controller on storyboard, go into Attributes Inspector and select "Is Initial View Controller".
Make your navigation controller Initial View Controller.
Then create a push-segue from button to target controller.
Then you can use following method to make some adjustments before pushing:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"TargetSegue"]) {
TargetViewController *vc = segue.destinationViewController;
//vc.items = nil;
}
}
Update:
There are more options:
If your initial view controller is tabbar: Add segue from one of the tabs to navigation controller which contains your view controller.
If your initial view controller is another navigation controller:
Remove navigation controller which contains your view controller. Then add the segue between the thirdViewController and the source from which it is presented. The you can use push segue between the button and the target view controller.
If you want to do it programmatically:
Remove navigation controller which contains your view controller. Push the thirdViewController from your currently presented navigation controller. Push the targetViewController from buttonAction.
Hope it will help :)
In your Xcode .Click the storyboard on the left side and on top select Editor->EmbedIn->Navigation controller .It will automatically add your navigation controller to the first view controller .Then it would work
You have to set the Navigation controller as the first controller
See before the Navigation controller there is the storyboard starting arrow
Under your IBAction method instead of using
[self presentViewController:addinvController animated:NO completion:nil];
use this code and check
[self.navigationController pushViewController:addinvController animated:YES];

Load view when button is clicked in Xcodes Storyboard

I just started to use Storyboard in Xcode. I have a starting view that has some buttons inside. Is there a way to load a special view when a button is clicked?
I only found this workaround:
-(IBAction)loadRegistration:(id)sender {
// load registration controller
UIStoryboard *storyboard = self.storyboard;
RegisterController *svc = [storyboard instantiateViewControllerWithIdentifier:#"RegisterController"];
[self presentViewController:svc animated:YES completion:nil];
}
You don't need any code to load a new view. You just control-drag from the button to the controller you want to present, and choose the segue type. If the controller with the button is in a navigation controller you can choose push or modal, if it's not, then you want to choose modal.
The way you did it seems ok. You can also connect the current View Controller to the one you want to present with a segue in the Interface Builder (ctrl + drag). When the button is tapped, you would call [self performSegueWithIdentifier:#"segue identifier"];. Of course, you set the id of the segue in the IB.
Even more simpler would be to connect the button with the new View Controller in IB (also ctrl+drag). This way you won't even need the IBAction.

Creating a segue programmatically

I have a common UIViewController that all my UIViewsControllers extend to reuse some common operations.
I want to set up a segue on this "Common" UIViewController so that all the other UIViewControllers inherit.
I am trying to figure out how do I do that programmatically.
I guess that the question could also be how do I set a segue for all my UIViewControllers without going into the story board and do them by hand.
I thought I would add another possibility. One of the things you can do is you can connect two scenes in a storyboard using a segue that is not attached to an action, and then programmatically trigger the segue inside your view controller. The way you do this, is that you have to drag from the file's owner icon at the bottom of the storyboard scene that is the segueing scene, and right drag to the destination scene. I'll throw in an image to help explain.
A popup will show for "Manual Segue". I picked Push as the type. Tap on the little square and make sure you're in the attributes inspector. Give it an identifier which you will use to refer to it in code.
Ok, next I'm going to segue using a programmatic bar button item. In viewDidLoad or somewhere else I'll create a button item on the navigation bar with this code:
UIBarButtonItem *buttonizeButton = [[UIBarButtonItem alloc] initWithTitle:#"Buttonize"
style:UIBarButtonItemStyleDone
target:self
action:#selector(buttonizeButtonTap:)];
self.navigationItem.rightBarButtonItems = #[buttonizeButton];
Ok, notice that the selector is buttonizeButtonTap:. So write a void method for that button and within that method you will call the segue like this:
-(void)buttonizeButtonTap:(id)sender{
[self performSegueWithIdentifier:#"Associate" sender:sender];
}
The sender parameter is required to identify the button when prepareForSegue is called. prepareForSegue is the framework method where you will instantiate your scene and pass it whatever values it will need to do its work. Here's what my method looks like:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"Associate"])
{
TranslationQuizAssociateVC *translationQuizAssociateVC = [segue destinationViewController];
translationQuizAssociateVC.nodeID = self.nodeID; //--pass nodeID from ViewNodeViewController
translationQuizAssociateVC.contentID = self.contentID;
translationQuizAssociateVC.index = self.index;
translationQuizAssociateVC.content = self.content;
}
}
I tested it and it works.
By definition a segue can't really exist independently of a storyboard. It's even there in the name of the class: UIStoryboardSegue. You don't create segues programmatically - it is the storyboard runtime that creates them for you. You can normally call performSegueWithIdentifier: in your view controller's code, but this relies on having a segue already set up in the storyboard to reference.
What I think you are asking though is how you can create a method in your common view controller (base class) that will transition to a new view controller, and will be inherited by all derived classes. You could do this by creating a method like this one to your base class view controller:
- (IBAction)pushMyNewViewController
{
MyNewViewController *myNewVC = [[MyNewViewController alloc] init];
// do any setup you need for myNewVC
[self presentModalViewController:myNewVC animated:YES];
}
and then in your derived class, call that method when the appropriate button is clicked or table row is selected or whatever.
I've been using this code to instantiate my custom segue subclass and run it programmatically. It seems to work. Anything wrong with this? I'm puzzled, reading all the other answers saying it cannot be done.
UIViewController *toViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"OtherViewControllerId"];
MyCustomSegue *segue = [[MyCustomSegue alloc] initWithIdentifier:#"" source:self destination:toViewController];
[self prepareForSegue:segue sender:sender];
[segue perform];
Guess this is answered and accepted, but I just would like to add a few more details to it.
What I did to solve a problem where I would present a login-view as first screen and then wanted to segue to the application if login were correct. I created the segue from the login-view controller to the root view controller and gave it an identifier like "myidentifier".
Then after checking all login code if the login were correct I'd call
[self performSegueWithIdentifier: #"myidentifier" sender: self];
My biggest misunderstanding were that I tried to put the segue on a button and kind of interrupt the segue once it were found.
You have to link your code to the UIStoryboard that you're using. Make sure you go into YourViewController in your UIStoryboard, click on the border around it, and then set its identifier field to a NSString that you call in your code.
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard"
bundle:nil];
YourViewController *yourViewController =
(YourViewController *)
[storyboard instantiateViewControllerWithIdentifier:#"yourViewControllerID"];
[self.navigationController pushViewController:yourViewController animated:YES];
For controllers that are in the storyboard.
jhilgert00 is this what you were looking for?
-(IBAction)nav_goHome:(id)sender {
UIViewController *myController = [self.storyboard instantiateViewControllerWithIdentifier:#"HomeController"];
[self.navigationController pushViewController: myController animated:YES];
}
OR...
[self performSegueWithIdentifier:#"loginMainSegue" sender:self];
well , you can create and also can subclass the UIStoryBoardSegue . subclassing is mostly used for giving custom transition animation.
you can see video of wwdc 2011 introducing StoryBoard. its available in youtube also.
http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIStoryboardSegue_Class/Reference/Reference.html#//apple_ref/occ/cl/UIStoryboardSegue
I'd like to add a clarification...
A common misunderstanding, in fact one that I had for some time, is that a storyboard segue is triggered by the prepareForSegue:sender: method. It is not. A storyboard segue will perform, regardless of whether you have implemented a prepareForSegue:sender: method for that (departing from) view controller.
I learnt this from Paul Hegarty's excellent iTunesU lectures. My apologies but unfortunately cannot remember which lecture.
If you connect a segue between two view controllers in a storyboard, but do not implement a prepareForSegue:sender: method, the segue will still segue to the target view controller. It will however segue to that view controller unprepared.
Hope this helps.
Storyboard Segues are not to be created outside of the storyboard. You will need to wire it up, despite the drawbacks.
UIStoryboardSegue Reference clearly states:
You do not create segue objects directly. Instead, the storyboard
runtime creates them when it must perform a segue between two view
controllers. You can still initiate a segue programmatically using the
performSegueWithIdentifier:sender: method of UIViewController if you
want. You might do so to initiate a segue from a source that was added
programmatically and therefore not available in Interface Builder.
You can still programmatically tell the storyboard to present a view controller using a segue using presentModalViewController: or pushViewController:animated: calls, but you'll need a storyboard instance.
You can call UIStoryboards class method to get a named storyboard with bundle nil for the main bundle.
storyboardWithName:bundle:
First of, suppose you have two different views in storyboard, and you want to navigate from one screen to another, so follow this steps:
1). Define all your views with class file and also storyboard id in identity inspector.
2). Make sure you add a navigation controller to the first view. Select it in the Storyboard and then Editor >Embed In > Navigation Controller
3). In your first class, import the "secondClass.h"
#import "ViewController.h
#import "secondController.h"
4). Add this command in the IBAction that has to perform the segue
secondController *next=[self.storyboard instantiateViewControllerWithIdentifier:#"second"];
[self.navigationController pushViewController:next animated:YES];
5). #"second" is secondview controller class, storyboard id.
I reverse-engineered and made an open source (re)implementation of UIStoryboard's segues: https://github.com/acoomans/Segway
With that library, you can define segues programmatically (without any storyboard).
Hope it may help.
A couple of problems, actually:
First, in that project you uploaded for us, the segue does not bear the "segue1" identifier:
no identifier
You should fill in that identifier if you haven't already.
Second, as you're pushing from table view to table view, you're calling initWithNibName to create a view controller. You really want to use instantiateViewControllerWithIdentifier.
Here is the code sample for Creating a segue programmatically:
class ViewController: UIViewController {
...
// 1. Define the Segue
private var commonSegue: UIStoryboardSegue!
...
override func viewDidLoad() {
...
// 2. Initialize the Segue
self.commonSegue = UIStoryboardSegue(identifier: "CommonSegue", source: ..., destination: ...) {
self.commonSegue.source.showDetailViewController(self.commonSegue.destination, sender: self)
}
...
}
...
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// 4. Prepare to perform the Segue
if self.commonSegue == segue {
...
}
...
}
...
func actionFunction() {
// 3. Perform the Segue
self.prepare(for: self.commonSegue, sender: self)
self.commonSegue.perform()
}
...
}

Resources