I got app with 2 view controllers, I'm typing values via NSStrings in Label and TextField in my first view controller and when I by pushing my navigation button go to my second view controller. When I return to my first view controller, I got entered early values. But when next after that I go to my second view controller - values entered via NSStrings in Label and TextField disappear. How to fix this that the values saved? I tried to use strong and copy properties but that not helps me.
I use segue and storyboards, segue with modal type, I use 1 navigation controller for first view controller. I got code only for modal type. First view controller is root for navigation
UPDATE
User entering values such as NSSting in first and in second VC. On navigation bar of first and in second VC there are bar buttons and with that user go throw VCs
type data in first VC -> go to second -> type data in second VC -> go to first(it saved data) -> go to second(it lost data)
I use that code to return to first VC from second:
[self dismissViewControllerAnimated:YES completion:nil];
Segues always instantiate new controllers, so when you go to the second controller for the second time, you're actually going to a new instance of that controller. If you want to go to the same instance, you can't use a segue. Instead you should make a property in your first controller that points to the second one, instantiate that second one, the first time you go to it, but not on any subsequent presentations (put in an if clause, and if the controller already exists, present it, if not, instantiate it first and then present it). The example below assumes that you have a custom controller of class SecondViewController, and that you've given it the identifier, "Second", in the storyboard.
#property (strong,nonatomic) SecondViewController *secondVC;
-(IBAction)presentSecondController:(UIButton *) sender {
if (! self.secondVC) {
self.secondVC = [self.storyboard instantiateViewControllerWithIdentifier:#"Second"];
}
[self presentViewController:secondVC animated:YES completion:nil];
}
Related
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
In my app, I need to go to another UIViewController with a button click, but when I did it in the new UIViewController it displays only what I set programmatically.
I used:
NewSubject *NewS = [[NewSubject alloc] initWithNibName:nil bundle:nil];
[self presentViewController:NewS animated:YES completion:nil];
"NewSubject" is the UIViewController I need to go too, however I want the computer to display also the stuff I set by the Storyboard.
Have you set in the Storyboard, in the NewSubject View Controller, in the third tab (Show Identity Inspector) the StoryBoard ID?
You should set it to some name, such as "NewSubject" and use it as follow:
NewSubject *NewS = [self.storyboard instantiateViewControllerWithIdentifier:#"NewSubject"];
[self.navigationController pushViewController:NewS animated:YES];
I want the computer to display also the stuff I set by the Storyboard.
If you're using a storyboard, -initWithNibName:bundle: is the wrong method to use. You can use UIStoryboard's -instantiateViewControllerWithIdentifier: method to create a new view controller that's defined in a storyboard, but the more typical approach is to have your button trigger a segue between the two view controllers.
Try this:
While editing your storyboard, control-drag from your button to the new view controller. A popup menu should appear that lets you choose how you want to transition between the view controllers -- push (push the new controller onto the top of the navigation stack), modal (present the view controller modally), etc. Pick the appropriate one.
In simple cases, you're done -- there's no need to write any code just to get the transition to happen. The segue takes care of creating the new view controller and performing the transition for you. However, you often want to pass some data from the existing view controller to the new one. If that's the case, implement -prepareForSegue:sender: in the existing view controller -- this method gives you a chance to pass whatever data you need. It'll look something like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// It doesn't hurt to check that it's the segue that you expect
if ([segue.identifier isEqualToString:#"MySegueIdentifier"]) {
NewViewController *newVC = segue.destinationViewController;
// This is your chance to set properties or call methods to pass data to the new view controller
newVC.foo = self.foo;
newVC.bar = self.bar;
}
}
My problem
I have a standard UIViewController. With the press of a button, it loads a form sheet modal view controller. When dismissing this modal view with the press of a UIBarButtonItem I call a method by doing:
ViewController *main = [[ViewController alloc] initWithNibName:nil bundle:nil];
[main updateLabel];
In the method -(void)updateLabel in the main ViewController I'm setting the text of a label, but the label won't change. But I know the function gets called, because if I do a NSLog(#"Method call test); instead of label.text = #"Test" I can see the message in console.
What am I doing wrong? It must be the way I'm calling the method in the main ViewController, because I can easily change the label anywhere else.
What I want to do:
When dismissing a modal view controller, I want a method to be called in the main view controller, and in this case change the text of a label.
Thanks for your help!
You're creating a new instance of ViewController with that code, not getting a pointer to the one you already have.
If ViewController is the controller that presented the modal view, then you can get a pointer to it with,
ViewController *main = self.presentingViewController;
A better way to do this would be to use the delegate pattern.
https://developer.apple.com/library/ios/documentation/general/conceptual/DevPedia-CocoaCore/Delegation.html
The following is a design pattern suggestion
The modal view controller shouldn't know how to dismiss itself, that is the responsibility of the presenting view controller. After all, it could have been presented in many different ways (modally, popover, push navigation). Using the delegate pattern, the modal view controller would tell its delegate that it should be dismissed when the bar button item gets pressed. The delegate, which is the presenting view controller, would then dismiss the modal view and update the label mentioned in your question.
I have a regular UINavigationController with a couple of views attached, which are working perfectly fine. Its RootViewController has a custom Menu-button on the top left, at the same place as the "Back"-button is on the attached views. When clicking this menu-button, the menu appears and presents five options.
Obviously, by clicking one of these option, you would be presented with the ViewController for that option.
I want to completely 'forget' the current ViewController, and move on to this new controller. Usually, I would do something like [self presentViewController....]; or [self.navigationController push..];, but in these methods the current ViewController will, I think, always exists 'below' the new presenting viewController (as you would return to this instantiation if using [self dismissViewController..];, I don't want this).
In the presenting ViewController there will be a menu-option to return back to the original controller, but I still want this to be a clean instantiation of it, and not just popping. By thinking ahead in time, I figured I would potentially create an infinite number of ViewControllers on top of each other by using the methods I know of this way.
I entered the world of iOS after the era of ARC began, so I have no clue how to release or deallocate such views, which I assume has relevance here.
The second View Controller is also supposed to be a root in a UINavigationController, and I'm not sure if it's best to use the same UINavigationController, or if I should present a new one, and dismiss the old. Essentially, I would like to replace the Navigation Controller's rootViewController from the rootViewController, but I don't see how that would be possible. Or possibly push to ViewController2, and then popping the rootViewController out of the hierarchy, leaving the new ViewController as the root, but then I assume I'd have problems with the navigational back-button(if it's even possible).
I figured it's just as easy to let ViewController2 be root at its own NavigationController, and presenting this NavigationController from ViewController1. The problem is, I want to completely remove everything that has to do with ViewController1 and its NavigationController from memory after presenting ViewController2, but I have no idea how.
I'm open to other solutions to my situation, but I'd also like an answer to how I can completely 'forget' a view after presenting another on general basis.
If you want to "forget" controllers, you can just replace the window's root view controller with a new one. The original one will be deallocated if you don't have any other strong pointers to it. I'm not sure I understand all of what you're trying to do, but for example, if you want controller 1 and controller 2 to both be root view controllers of a navigation controller, and you don't want controller 1 around when you switch to 2, then do something like this from controller one:
SecondViewController *second = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:second];
self.view.window.rootViewController = nav;
This will switch out the controllers, and controller 1 and its navigation controller will be deallocated (assuming that the only thing with a strong pointer to the navigation controller was the window, through its rootViewController property).
Create a menu UIViewController and add it as a root to the UINavigationController on launch. Add 1st UIViewController as a child controller to menu UIViewController when viewDidLoad of menu controller is called. When you click menu to show 2nd UIViewController, remove the 1st UIViewController from menu view controller and add 2nd UIViewController to child of the menu view controller. You can put NSLog in both, 1st and 2nd view controller's dealloc method to check if its released or not. Logic is like this
//inside menuvc class
#interface MenuVC{
UIViewController * currentVC; // current child controller to menuVC
}
-(void)viewDidLoad{
[self addChildController:firstVC]; //to add view controller 1 intially
currentVC = firstVC;
}
-(void)add2ndChildController{
[currentVC removeFromParentViewController];
[self addChildController:secondVC]; //to add view controller 2 when needed
currentVC = secondVC;
}
// dealloc of 1st vc
-(void)dealloc{
NSLog(#"first vc released");
}
I just wrote some sample logic of what I explained before, you have to generalize this logic if you feel its right for you. Hope it helps :)
I have a tab bar controller with 3 view controllers and one navigation view controller in it.
That navigation view controller has a table view controller and detail view.
In my first view controller (first tab) there are three buttons. I want the first button to load the detail view in the navigation controller. (as seen on image below)
Storyboard
How can i achieve this ?
I have tried calling the method that performs the segue in LocationsTableViewController, but that gives me the error "Receiver () has no segue with identifier 'addLocation'". Although a segue "addLocation" certainly exists.
Method connected to button in StartViewController:
- (IBAction)addLocationView:(id)sender {
LocationsTableViewController *LTVC = [[LocationsTableViewController alloc] init];
[LTVC addLocation];
}
LocationsTableViewController:
-(void)addLocation
{
[self performSegueWithIdentifier: #"addLocation" sender: self];
}
Your "addLocation" segue is from the Locations Table View Controller to the Add Location View Controller, so the segue exists on the LocationsTableViewController. That is correct. However, if your current view controller isn't LocationsTableViewController, it doesn't make sense to call that segue.
You have a few options:
Storyboard Option #1: Make a new segue from StartViewController to AddLocationViewController, and perform that segue in addLocationView:.
Storyboard Option #2: Make a new segue from the button to the AddLocationViewController, and remove your IBAction. The storyboard will automatically call that segue when the button is clicked.
Programatic Option: Instantiate a new AddLocationViewController and push it onto the navigation stack: [self.navigationController pushViewController:[[AddLocationViewController alloc] init] animated:YES].