IOS Objective C - error while passing parameter between two view controllers - ios

I have two viewControllers :
RegisterViewController & Register2ViewController
I have a segue from RegisterViewController to Register2ViewController.
I want to set the value of a the textfielduser in Register2ViewController with a value that the user entered in a the textfieldemail in RegisterViewController.
so far here is what i've done.
in RegisterViewController.m
- (IBAction)NextPage:(UIButton *)sender {
[self performSegueWithIdentifier:#"toRegister2" sender:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"toRegister2"]) {
Register2ViewController *controller = (Register2ViewController *)segue.destinationViewController;
controller.user.text = self.email.text;
}
but when I run and fill the values of textfields in RegisterViewController and go over to Register2ViewController the textfield user is empty, can you help me please? Thank you

controller.user.text = self.email.text;
At this time, the Register2ViewController is not loaded in the memory yet, that's why you are facing this issue.
Keep a NSString property in Register2ViewController.h and set the value of that string here.
Then, in viewDidLoad of Register2ViewController, set that string as text of UITextField.

Instead of directly passing value to textField, try passing text using NSString. Declare #property (strong,nonatomic) NSString *userName; in Register2ViewController. Then pass value to string like
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"toRegister2"]) {
Register2ViewController *controller = (Register2ViewController *)segue.destinationViewController;
controller.useName= self.email.text;
}
Then in viewDidLoad of Register2ViewController ,set string on textField like this self.user.text=self.userName.
Try doing this.

Related

Loading another view in the same viewController clears non UI properties

I have a UIViewController controlling several different views in Xcode. I want to set a label on the incoming view using information from the current view. I know labels and other UI elements get reset when the view is loaded, but my non UI #property is being set to nil as well.
Here is my property:
#property (strong, nonatomic) NSString* username;
Here is the code that sets it:
//NSLog(#"%#",dict);
if ([dict[#"login"] intValue]){
[self performSegueWithIdentifier:#"JoinSuccess" sender:sender];
self.username = dict[#"user"];
Here is the code that tries to use it:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"%#", self.username);
self.welcomeLabel.text = [NSString stringWithFormat:#"Welcome, %#",self.username];
}
I've tried setting username both before and after performSegueWithIdentifier, but in either case when I try to reference it in viewDidLoad the value is nil. Any idea as to why it's reseting my #property? My guess is maybe it's creating a new instance of my viewController. If that's the case, how can I pass the needed variable?
As you said the viewController will be created again when ever you call performSegueWithIdentifier. You could set the value in the new instance. You can do this in
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
YourViewController *vc = [segue destinationViewController];
vc.username = dict[#"user"];
}
you have to add another method to pass value from one view controller to another view controller .
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
nextViewcontroller *nextViewcontrollerObjt = [segue
destinationViewController];
// apply setter to set value of next view
nextViewcontrollerobject.title = nextViewControllerTitleString;
nextViewcontrollerobject.variable_1= currentView_variable1;
nextViewcontrollerobject.variable_2 =currentView_variable2;
}

Pass info to viewcontroller on storyboard

I'm new using storyboards and I'm facing this situation: A uinavigationcontroller contains a view controller (root controller) which contains ten buttons linked each one of then through storyboard to the same view controller.
The behavior of the second view controller depends on the button tapped in the first view controller, but how can identify which button is tapped (like tag value) and pass this info to second view controller?
Thank you.
To add on Daniel's answer:
First, add a public property onto your secondVC that is accessible from your first VC:
#interface SecondViewController : UIViewController
#property (nonatomic) int buttonTagClicked;
#end
You need to set tags up on your UIButtons. This is either done in storyboard or programmatically in your code. I would create a generic IBAction that each button is linked to. You can extract the tag off the button through the sender parameter later.
- (IBAction)buttonClicked:(id)sender
{
[self performSegueWithIdentifier:#"pushSegue" sender:sender];
}
That is linked up to
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"pushSegue"]) {
SecondViewController *destinationVC = (SecondViewController *)[segue destinationViewController];
UIButton *selectedButton = (UIButton *)sender;
destinationVC.buttonTagClicked = selectedButton.tag;
}
}
You can set a segueIdentifier for each connection. Then in your ViewController you could trigger an action based on the identifier you set.
e.g.:
If you select your connection in storyboard you can name it:
And in your ViewController you can trigger an action based on the identifier like this:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"segue1"]) {
UIViewController *destinationVC = [segue destinationViewController];
destinationVC.property = ...;
}
}

Set UITextField text property in prepareForSegue

I have a textField in my ViewController1. I have a push segue to my ViewController2 which also has a textField. I need to set the textField.text in my ViewController2 to be equal to the text in the textField in my ViewController1. Here's the code I have:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqual:#"ViewController2"])
{
ViewController2 *VCT = [segue destinationViewController];
VCT.title = #"View Controller #2";
VCT.textField.text = self.textField.text;
}
}
The title setter works just fine. Why is the textField not working?
You cannot set the text of the UITextField (and any other components like UILabel and UITextView) in the prepare for segue, because all view components of the recently allocated controller are not initialized yet (at this time, they are all nil), they only will be when the viewController is presented (and it's view loaded).
You have to create a NSString property in the presented viewController, and then, somewhere inside your another view controller, like viewDidLoad, set the text of the textField as this property value.
Like this:
In the viewController that will present the another viewController:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"ViewController2"])
{
ViewController2 *vc2 = [segue destinationViewController];
vc2.myString = self.textField.text;
}
}
And inside the presented viewController:
- (void)viewDidLoad
{
[super viewDidLoad];
(...)
self.textField.text = self.myString;
}
Check and see if "VCT.textField" is not nil at that point. I suspect that you'll find it is nil.
You either need to expose it via "#property (strong) IBOutlet UITextField * textField" or you need to store the string somewhere else (e.g. a "NSString" property?) which then loads the text field when the view is fully loaded.

How do I set the title on the destination view controller during prepareForSegue:

I want to simply set the title on my destination view controller so that it shows in its navigation controller's navigation bar in the prepareForSegue: method however setting its title or navigationItem like so:
[segue.destinationViewController setTitle:#"doesn't work"];
[segue.destinationViewController.navigationItem setTitle:#"this either"];
doesn't work possibly because the destination's view controller's view isn't loaded yet. Can I do this without creating a custom destination view controller?
Try accessing your ViewController that is embedded in the UINavigationController like this.
First you give your segue an identifier in the interface builder, then you access the segue in the prepareForSegue method and set the title by accessing the topViewController property of the navigation controller you segue to.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"yourSegueIdentifier"]) {
UINavigationController *navController =
(UINavigationController*)[segue destinationViewController];
YourViewController *destViewController =
(YourViewController* )[navController topViewController];
destViewController.navgationItem.title.text = #"Your new title";
}
}
This is for a segue into another UITableView
Set a public NSString property in the destination UITableViewController file.
#property (strong, nonatomic) NSString *navBarTitle;
Override the setter in the .m file just to be sure.
- (void) setNavBarTitle:(NSString *)navBarTitle
{
_navBarTitle = navBarTitle;
}
In the originating tableView's segue method, pass whatever string you need in the title.
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString: #"userDetails"]) {
UsersActivitiesTableViewController *destinationController = segue.destinationViewController;
//Get the index path of the cell the user just clicked
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
//Grab the object from the array of users if the next view requires a specific title for a user name etc.
UserMO *thisUser = [self.users objectAtIndex:indexPath.row];
//Pass the string you want as the title to the public NSString property
destinationController.navBarTitle = thisUser.name;
}
}
And now for the important bit....
In the destination controller, get the top controller of the view and set the title property, after the view is loaded, and before it has been displayed:
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController topViewController].title = self.navBarTitle;
}
If you want a static title this can now (i.e., in Xcode 4.6.3) this can be done in Storyboard simply by setting the title in the nav bar on the relevant view controller.
If however you want the nav bar title to change according to what view is being segued to, e.g., a detail of a particular table row, as far as I know that needs to be set programmatically.
It took me FOREVER (newbie, sigh!) to figure out how to modify Julian Vogels' correct answer to call the key I wanted to use. Here's what worked:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"DetailSegue"]) {
// Fetch Item
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSDictionary *item = [self.groceries objectAtIndex:[indexPath row]];
// Configure Detail View Controller
TPDetailViewController *vc = [segue destinationViewController];
vc.navigationItem.title = [item objectForKey:#"name"];
[vc setItem:item];
}
If the segue is a push segue - which it should be if you're using a UINavigationController - then the destination view controller is automatically added to the window hierarchy, and you don't even need to identify the UINavigationController:
if ([segue.identifier isEqualToString:#"yourSegueNameHere"]) {
[segue.destinationViewController setTitle:#"yourTitleHere"];
}

iOS: How to use the same Popover ViewController to controller two separate buttons

In RootViewController I have a button *flop1 that when clicked opens PopViewController through segue *segPop and when a selection is chosen and the popover closes, button *flop1 's image is changed.
I would like to have multiple buttons like *flop1, each which can be populated by its own choosen image, all while using the same PopViewController.
I have connected *flop2 to the same PopViewController, through seque *segPop2.
RootViewController.m
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"segPop"]) {
currentPopoverSegue = (UIStoryboardPopoverSegue *)segue;
pvc = [segue destinationViewController];
[pvc setDelegate:self];
[pvc setStrPassedValue:[tfUserText text]];
} else if ([[segue identifier] isEqualToString:#"segPop2"]) {
currentPopoverSegue = (UIStoryboardPopoverSegue *)segue;
pvc = [segue destinationViewController];
[pvc setDelegate:self];
[pvc setStrPassedValue:[tfUserText text]];
}
}
// PopViewControllerDelegate callback function
- (void)dismissPop:(NSString *)value {
NSString *imagefile;
imagefile = [NSString stringWithFormat:#"%#.png",value];
[flop1 setImage:[UIImage imageNamed:imagefile] forState:UIControlStateNormal];
[[currentPopoverSegue popoverController] dismissPopoverAnimated: YES]; // dismiss the popover
}
#end
How do I create an IF ELSE statement in my
- (void)dismissPop:(NSString *)value {
to populate *flop2 button with a new image while keeping *flop1 image from changing as well?
I'm sorry if this all seems messy, I have zero programming education and am trying all of this from imitation.
Thanks
In this method:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
sender is a pointer to the object that invoked the segue (in your case, the button). You can define a property in your popoverViewController:
#property (strong, nonatomic) UIButton* buttonThatInvokedMe;
set it to the invoking button in your prepareForSegue:
[pvc setButtonThatInvokedMe:sender];
and then return it to a modified dismssPop:
- (void)dismissPop:(NSString *)value buttonThatInvokedPopover:(UIButton*)button {
NSString *imagefile;
imagefile = [NSString stringWithFormat:#"%#.png",value];
[button setImage:[UIImage imageNamed:imagefile] forState:UIControlStateNormal];
[[currentPopoverSegue popoverController] dismissPopoverAnimated: YES];
// dismiss the popover
}
Which you would call from your popOverVC like this:
[self.delegate dismissPop:value button:buttonThatInvokedMe]
No if else required... you should also be able to dispense with the if else construction in your prepareForSegue.
You will want to make your button pointer-passing types consistent to avoid compilter warnings. If you are certain that the Segue will only be invoked by UIButton types, change your prepareForSegue signature to typecast the sender:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(UIButton*)sender
The other way to do this is to leave it as id type, but change your pointer type in the popOverViewController to id and pass it back to the delegate method as id - but then you will need to typecase it to UIButton before calling the setImage:forState method as this expects a UIBUtton type..
protocols
To make this all work without compiler warnings you will also need to declare a protocol for the dismissPop: delegate method or use performSelector-type method to invoke it indirectly.

Resources