How do you make a programmatic segue?
I tried this:
[self performSegueWithIdentifier:#"next" sender:self];
but it only gives me this console message:
Snapshotting a view that has not been rendered results in an empty snapshot.
Ensure your view has been rendered at least once before snapshotting or snapshot after screen updates.
What I want to do is Have a button which triggers a image picker to appear. When the user has selected an image, a segue to the next view controller is performed.
I don't have enough reputation to add a comment but if you are attempting to present UIImagePickerController I would advice you to read this post
You could prepare the segue before showing it (Supposing you already connected the segue in the Storyboard and named it)(You wait for the execution block of the picker to complete before performing the Segue).
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
if ([[segue identifier] isEqualToString:#"next"]) {
NextViewController *vc = [segue destinationViewController];
// Call anything from the vc
}
}
Hope you get some clues.
Related
I'm new on Stackoverflow and I'm currently learning XCode from scratch and I'm in a process of making a Single Page Application with options.
Anyone knows how to efficiently make a simple menu with multiple selectable UIButtons that make the main ViewController display different datasets depending on the selection in XCode?
Tried different things (creating SecondViewController for example but can't figure out how to pass data from it to main ViewController).
Any help will be greatly appreciated.
Refer this:
https://www.appcoda.com/storyboards-ios-tutorial-pass-data-between-view-controller-with-segue/
How to pass prepareForSegue: an object
Simple Test from above Answer Reference:
Simply grab a reference to the target view controller in prepareForSegue: method and pass any objects you need to there. Here's an example...
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
if ([[segue identifier] isEqualToString:#"YOUR_SEGUE_NAME_HERE"])
{
// Get reference to the destination view controller
YourViewController *vc = [segue destinationViewController];
// Pass any objects to the view controller here, like...
[vc setMyObjectHere:object];
}
}
REVISION: You can also use performSegueWithIdentifier:sender: method to activate the transition to a new view based on a selection or button press.
For instance, consider I had two view controllers. The first contains three buttons and the second needs to know which of those buttons has been pressed before the transition. You could wire the buttons up to an IBAction in your code which uses performSegueWithIdentifier: method, like this...
//When any of my buttons are pressed, push the next view
- (IBAction)buttonPressed:(id)sender
{
[self performSegueWithIdentifier:#"MySegue" sender:sender];
}
// This will get called too before the view appears
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"MySegue"]) {
// Get destination view
SecondView *vc = [segue destinationViewController];
// Get button tag number (or do whatever you need to do here, based on your object
NSInteger tagIndex = [(UIButton *)sender tag];
// Pass the information to your destination view
[vc setSelectedButton:tagIndex];
}
}
Hope this help but please go through refernces!
I am trying to transition between view controllers with a segue. It is navigating correctly but it is running twice.
Here is my code:
- (IBAction)onActionNext:(id)sender {
if ([[nameField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]isEqualToString:#""]) {
}else if([[emailField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] isEqualToString:#""]){
}else if([[mobileField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] isEqualToString:#""]){
}else{
[self performSegueWithIdentifier:#"VerifyNext" sender:sender];
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([[segue identifier] isEqualToString:#"VerifyNext"]) {
// Get destination view
OTPSceneViewController *vc = [segue destinationViewController];
[vc setTitle:#"myapp"];
}
}
If even after commenting this line segue still run then as #mikealter said segue is connected your button. Check if when you check for when you click segue what it highlights.
A button like:
Or A View Controller like:
If you fall in first case that means your segue is connected to a button and, that is the reason why it opens next page even if you comment your code. And 2 times when you keep code(one from storyboard and another from code).
Edit:
If you want to call next page from code only. Remove Segue. Then reconnect it with view controller like:
First, whenever you create a segue (i.example) FROM a Button TO a View Controller, you are creating the link between VC1 and VC2.
If you run your project you will see that the segue works navigating from one VC to the other one.
This means that it already performs the segue, so if you declare an ACTION for your button and make a call to - perform segue... - it will run twice.
Note: if you call performSegueWithIdentifier is probably because you want to pass some data via SENDER. In that case you (obviously) need to call the segue ONCE, so instead of creating the segue from the button to the next VC, (first delete that segue), create a new one FROM the VCOrigin to VCDestination -> there are many ways to do it, but from the Interface Builder is as simple as right click on the top yellow rounded icon and drag&drop on the destinationVC. Don't forget to set the identifier on the Attributes Inspector.
Now, in your button~Action make the call to performSegueWithIdentifier and pass the data.
if you stop storyboard segue use following method:
override func shouldPerformSegueWithIdentifier(identifier: String,sender: AnyObject?) -> Bool {
return false
}
You don't even add
[self performSegueWithIdentifier:#"VerifyNext" sender:sender];
in onActionNext method if you add the segue in storyboard
If you want to navigate to next view controller use above line.
Preparing for the Segue
In order to pass information from one view controller to another using
the UIStoryboardSegue object we’ll need to take advantage of the
current view controller’s prepareForSegue:sender: method.
But If you call both,it calls two times.So make sure that whether you want to pass information or data to next view controller or just navigate the view.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"prepareForSegue: %#", segue.identifier);
if([segue.identifier isEqualToString:#"VerifyNext"])
{
VerifyNextViewController *verifyNVC = segue.destinationViewController;
verifyNVC.name = #"Prashabt";
verifyNVC.id = #"1234";
}
else if([segue.identifier isEqualToString:#"VerSeg"])
{
AnotherViewController *anotherVC = segue.destinationViewController;
anotherVC.name = #"Sharma";
anotherVC.id = #"3245";
}
}
have a look of this question this may sure rectify
or there is another way to navigate to another view controller using below code.
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [mainStoryboard instantiateViewControllerWithIdentifier:#"viewControllerName"];
[self.navigationController pushViewController:vc animated:YES];
make sure you give identity to the view controller using identity inspector see image.
I have a simple app with 2 screens.
When I press a button to go from the first to the second, everything is performed successfully (including animation). However, when I click the back button on the second screen, I get the following warning:
Warning: Attempt to present <getTextViewController: 0x8f6aa30> on <SecondViewController: 0x946cc80> whose view is not in the window hierarchy!
EDIT: Please don't refer me to other questions regarding above warning - I already saw those, and they refer to other issues.
However, it still switches back to the first screen. Yet, the animation of the segue does not perform.
Also: Information (such as inputted text) in the first screen remains when I return to the first screen, while information in the second screen resets every time the screen comes up.
Here is how I call both operations:
Segue from View 1 to View 2:
Name: F21, Style: Modal, Transition: Cross Dissolve, Animation: True.
Segue from View 2 to View 1:
Name: F12, Style: Modal, Transition: Cross Dissolve, Animation: True.
Code in getTextViewController.m (View 1):
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([[segue identifier] isEqualToString:#"F21"]){
UIViewController *v = [segue destinationViewController];
[self dismissViewControllerAnimated:NO completion:nil];
v = self;
}
}
-(void)performSegue:(NSString*)str{
[self performSegueWithIdentifier:str sender:self];
}
//In some other method:
[self performSegue:#"F21"];
Code in SecondViewController.m (View 2):
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([[segue identifier] isEqualToString:#"F12"]){
UIViewController *v = [segue destinationViewController];
[self dismissViewControllerAnimated:NO completion:nil];
v = self;
}
}
-(void)performSegue:(NSString*)str{
[self performSegueWithIdentifier:str sender:self];
}
- (IBAction)goBack:(id)sender {
[self performSegue:#"F12"];
}
I would very much appreciate any help to understand why the first segue works while the second doesn't.
Thank you,
Dean
NOTE: Here is the full project - https://github.com/dean13-meet/firstIOSApp
EDIT: Updated git.
Im not exactly sure what you're trying to do in your prepareForSegue, their is no need to be dismissing VC's there. If you want to have a simple app where you go from VC1 to VC2 and then back again, your best bet is to use a segue and an unwindSegue.
So in your storyboard control drag from a button on VC1 to VC2 and select your segue type. Then in VC1.m setup the unwind segue such as:
- (IBAction)unwindFromViewController:(UIStoryboardSegue *)segue
{
//empty implementation
}
Finally, in your VC2 control drag from the back button to the green exit icon on VC2 and select your unwindFromViewController method.
That should do what you're looking for.
For the sake of simplicity, I would suggest using a push segue opposed to modal because it takes care of all the back buttons for you. If you don't like the idea of a navigation controller however, try dismissing the view with the following: Moving back from a Controller to a previous one
Hello I have a button that must present a modal view controller when tapped
Here is the action:
- (IBAction)addNewLevelAction:(id)sender
{
[self performSegueWithIdentifier:kNewLevelConfigureSegue sender:self];
}
in prepareForSegue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:kNewLevelConfigureSegue]) {
PSLevelConfigViewController *dest = (PSLevelConfigViewController *)[segue destinationViewController];
dest.delegate = self;
}
}
However when I tapp it I get:
Warning: Attempt to present <PSLevelConfigViewController: 0x98cbd00> on <UINavigationController: 0x98aac70> while a presentation is in progress!
Why is this? There is no other presentation there...
If you perform the segue programmatically, the segue must be connected to the controller and not directly to the button.
Check if your storyboard is set correctly (post some screenshots if you need help).
In such situation, if your segue is connected to the button AND, at the same time, to an action that performs it programmatically, your segue will be performed twice, and the second perform will cause that error.
I have a view controller with 2 different segues that goes to 2 different view controller,and i have to implement the cancel button in both the controllers.When i press the cancel button,in both the controller,the view will return to the initial view controller.My question is how can i implement the buttons?When i try with this code the compiler warning:Multiple declaration of method "cancel:" found and ignored.Thank you.
interface:
-(IBAction)cancel:(UIStoryboardSegue *)segue;
-(IBAction)done:(UIStoryboardSegue *)segue;
-(IBAction)cancel:(UIStoryboardSegue *)segue;
implementation:
-(IBAction)done:(UIStoryboardSegue *)segue
{
if([[segue identifier] isEqualToString:#"ReturnInput"]){
AddSightingViewController *addController = [segue sourceViewController];
if (addController.birdSighting) {
[self.dataController
addBirdSightingWithSighting:addController.birdSighting];
[[self tableView]reloadData];
}
[self dismissViewControllerAnimated:YES completion:NULL];
}
}
-(IBAction)cancel:(UIStoryboardSegue *)segue
{
if([[segue identifier] isEqualToString:#"CancelInput"]){
[self dismissViewControllerAnimated:YES completion:NULL];
}
}
I'm not sure of what you're trying to do. But I think the cancel method needs to be in the 2 child View Controllers, not in the main one. One for each controller (and one cancel button for each view). That way you won't have any problems with multiple declarations of a method.
From your code I conclude that you are using (or want use) exit segues for canceling.
First, you should only have one method declaration and implementation for your cancel method in the initial view controller. In your storyboard create exit segues by control-dragging from your cancel buttons to the green exit icon blow the view controller and select the cancel method defined in the initial view controller. Do that for both view controllers. You should also give your exit segues different identifiers in your storyboard (you need to select the segue in the Document Outline to change its identifier).
Then your cancel method in your initial view controller can look something like this:
-(IBAction)cancel:(UIStoryboardSegue *)segue
{
if([[segue identifier] isEqualToString:#"CancelInput1"]) {
// Do something
} else if([[segue identifier] isEqualToString:#"CancelInput2"]) {
// Do something different
}
}
If you don't want to do anything when canceling just leave the method empty.
If you wan't to go back you need to implement an unwind segue.
To do this, define a method to go back on the original view controller (the one you want to go back). You can leave the method empty.
- (IBAction)methodName:(UIStoryboardSegue *)segue
{
}
Then on IB ctrl + drag from the button (or from the view controller) to the green "exit" icon. Select the methodName from the popup menu. If you did it from the view controller set the identifier on the segue and call it with performSegueWithIdentifier: from the button action.
Considerations:
The method name will be detected in every view controller on the storyboard.
You can define the same method name in different view controllers, but when you execute the unwind segue, you will go back to the most recent on the navigation path.