I'm facing the following problem during the implementation of my app.
I've a tabbed application and clicking on each tab I can access to the corresponding view: for example, clicking on tab2 opens view2. But I can access to view2 also by clicking on a button on the view1 that is made as follows:
...
[buttonToView2 addTarget:self action:#selector(gotoView2) forControlEvents:UIControlEventTouchUpInside];
...
where:
- (void)gotoView2
{
//execute segue programmatically
[self performSegueWithIdentifier: #"View2Segue" sender: self];
}
View2 has a table that shows data of an array populated with data from the internet (in viewDidAppear method).
So, both selecting tab2 or clicking the button should bring the user to the destination view2.
This works but has a different behavior in the two cases:
If I click on the tab, the table is already populated with data while the application retrieves information from the internet
If I click the button and I perform the segue, the table is empty while the application retrieves information from the internet
Why? Maybe because of selector invoked by the button is executed on a different thread?
Any ideas please?
Regards,
yassa
Everytime a Segue is performed it creates a new instance of the destinationViewController (in this case view2). Meaning you have 2 separate instances of view2.
Related
I have a MainViewController which is a table view controller, with custom cells where the user can select some data. There is a button on this MainViewController that goes to PreferencesViewController, which has two buttons on the navigation bar, one for back (it is wokring now good), and the other one for save (here is my problem)
This is a screenshot of the navitation bar in the PreferencesViewController:
I drag a segue from the save bar button back to the MainViewController.
my problem
when I hit save, the MainViewController appears, but without saving the values the the user has already selected. sounds like a new instance of this MainViewContoller is being created.
What am i missing here? what other approach i should have already used please?
You need to connect your save button to an IBAction, not a segue.
In that IBAction, do whatever you need to do to save your data, and then do a dismissViewController:animated: call yourself in code.
If you wanted to use a segue you wouldn't be able to (easily) save your data, and yes, it creates a new instance.
An alternative would be to connect your save button to an unwind segue, rolls back, or unwinds, one or more segues to get back to a previous view controller. To do that you'd have to put your save logic in prepareForSegue (with code to test which segue is being invoked and only save in response to the save segue.)
i found the solution myself using:
1- custom delegate:
2- self.navigationController?.popViewControllerAnimated(true)
In my test project I have a ViewController and a TableViewController controller embedded in a Navigation Controller. The ViewController is the main view, and the user can navigate to the TableViewController and then return back to the ViewController.
I am using a 'push' segue when going from ViewContoller>TableViewController, and the TableViewController is dismissed using [self dismissViewControllerAnimated:YES completion:nil]; when the user wishes to go back to ViewController.
In ViewController, I have a button that changes the text on a label:
-(IBAction)onButtonPress:(id)sender {
_myLabel.text = #"New Label Text";
}
When navigating to TableView, and then back to ViewController, the change in the _myLabel.text has been lost and the original text is restored. What is the best way to ensure UI data is retained when navigating between views? I might only have one label in this project, but at some point I will have many UI elements, for example, WebViews that need to keep a page loaded when the user navigates away and then comes back.
What would you suggest is the best method to implementing this?
Thanks for your time.
First of all, View is your data representation, any data is your Model. So you may store Model with its entities and values. Your controllers manage data to represent it on View or to change Model according to user actions in View.
So add some Model-object for storing _myLabel.text. And use this object for both controllers in your app.
Try to remove setting the text from the ViewWillAppear or ViewDidAppear method, put it in ViewDidLoad.
I am making an iOS app where the user starts in the main menu (see figure).
When the user clicks button1, it triggers a segue (1) that takes him to a configuration wizard. On the other hand, clicking button2 takes the user to a configuration listing (showing what is already set), this also using a segue (2). Both these view controllers have a back button, that takes the user back to the main menu by calling
[self dismissViewControllerAnimated:YES completion:nil];
What I'm now struggling to implement, is a way to make the transition from the configuration wizard to the configuration listing.
When the user has made his choices in the wizard, and pushes the save button, I want this to take him directly to the configuration listing view. At the same time, the wizard view controller should be "forgotten", that is when the user now pushes the back button2, it should still take him back to the main menu. This means that I cannot just trigger a segue to the listing from the wizard, since then the wizard would still be there, "behind" the listing view, and would become visible when back button2 was pressed.
Any ideas on how to smoothly implement this?
You can add a segue from Configuration Wizard to List of Configurations. To avoid going back to Configuration Wizard store the Main Menu ViewController pointer and say popToViewController API for navigation.
Code sample where popToViewController is being used.
NSArray * controllerArray = [[self navigationController] viewControllers];
for (UIViewController *controller in controllerArray){
//Code here.. e.g. print their titles to see the array setup;
//NSLog(#"%#",controller.title);
if ([controller.title isEqual:#"ViewTitle"]) {
[self.navigationController popToViewController:controller animated:YES];
}
}
Hope this helps.
At Configuration Wizard screen, use presses save
[self.navigationController pushViewController:listOfConfigurationViewController animated:YES];
At this time, your stack is :
Main View Screen -> Configuration Wizard Screen -> List Of Configuration Screen
When uses presses back button at List Of Configuration Screen
// you will come back to Main Screen View
[self.navigationController popToRootViewControllerAnimated:YES];
After struggling for days on firing a segue conditionally, I managed to solve it thanks to Simon's answer here. Please take a moment to have a look or you might not understand what I'm talking about below. I didn't copy paste his answer because he's already explained it nicely over there.
Now I've faced a new question. What if I have multiple View Controllers that I want to segue to from one View Controller?
To explain it further : Say I have one MainViewController with 2 buttons. When clicked upon each button, it should segue to their respective View Controller. First button to FirstViewController and the second button to SecondViewController.
The method described in Simon's answer can be used when you segue from one View Controller to another View Controller. Since in that method, you tie the segue to the View Controller itsrlf and not to the button, you have only one segue with an identifier for that particular View Controller. Therefore I cannot distinguish between the button taps separately.
Is there a workaround to solve this problem?
Thank you.
It might be bit premature to say this but I guess you should look into Segue more deeply.
Yes you can perform segure from button. Just control click the button and drag the cursor to view controller you want it SEGUE'd. And from my understanding only condition there is each button tap results a segue to a fixed view. There is no condition there.
Also, you can push the navigation controller manually by
YourViewController *destViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"YourDestinationViewId"];
[self.navigationController pushViewController:destViewController animated:YES];
UPDATE:
prepareForSegue is too late to stop a segue from proceeding. Yes you can create multiple segues from your view to other view controllers. And in this case you have to do so. Don't reate a segue from button, just define a IBACtion on the button click you can do the validation from there,
if(validationSuccess) {
[self performSegueWithIdentifier:#"segue1" sender:self];
}
if you are using ios6
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
return YES on validation success and NO on failure to stop it from proceeding.
I suggest you look a bit at reworking your code logic.
If I understand correctly, you have a VC (embedded in a Nav. Controller) with 2 buttons and you have figured out how to segue each button to a different VC.
Your problem is you want to make sure that even if one of the buttons are pressed, a validation is done before an action takes place. I would advise this is bad User Interface design because the user has the illusion that this button might do something and then they click it and nothing happens.
UIButton can be connected to IBActions (to initiate actions) and IBOutlets (to set their properties). If this is a button created in IB directly, I would connect it to your class as an Outlet property:
#property (nonatomic,weak) IBOutlet UIButton* myButton;
And then set its enabled value:
self.myButton.enabled=NO;
This will keep the button and dim it. This is much better UI design and the user knows they should not press the button because some condition is not satisfied.
I would rework the code so that you set this value as disabled by default for example and enable it appropriately in your code whenever your "condition" is satisfied.
Obviously if this button is created programmatically (in your code without IB) then it is easy to just use the second command above.
Hope this helps.
I just wrote another way to call multiple detail views from a single table. Each cell could essentially make a different view be displayed. The code is similar to what you see in this post but you essentially use identifiers and attributes on the list item to determine which view to show.
https://codebylarry.com/2016/07/15/multiple-detail-views-in-swift/
override func tableView(tableView: UITableView,didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == 1 {
self.performSegueWithIdentifier("secondView", sender: self)
} else {
self.performSegueWithIdentifier(“others", sender: self)
}
}
Here how my storyboard looks like:
Initially when the users taps one of the squares, scene passes to the second one. At this point when the user closes the application and reopens it I want the second scene to come up.
I dont mind if first scene loads and then passes to the second one but I want second scene to show up.
Thanks in advance..
EDIT: I read that I can use generic segue but even if I create a generic segue with control drag from first view controller to the second one and using the code below nothing happens:
[self performSegueWithIdentifier: #"switch" sender: self];
SOLUTION:
You got to have a navigation control :)
In order to user the code below:
[self performSegueWithIdentifier: #"switch" sender: self];
You need to have a navigation control.