I want to create a game which is basically ask your buddy to put a word. And you will guess what word has been entered. For that reason, I have to pass guesword from FirstViewController to SecondViewController.
First View Controller
- (IBAction)doneBtn:(id)sender {
self.guessWord = [enterTF.text lowercaseString];
NSLog (#"Guessword s %#", guessWord);
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
NSLog (#"%#", [segue identifier]);
if ([[segue identifier] isEqualToString:#"F2S"])
{
// Get reference to the destination view controller
SecondViewController *gvc = [segue destinationViewController];
// Pass any objects to the view controller here, like...
gvc.guessWord =self.guessWord;
}
}
Second View Controller
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"%#",guessWord);
}
In the SecondViewController guessword output "null". Why am I getting null?
In the second view controller, declare your variable in the .h file, say a string type:
#property (nonatomic, strong) NSString *someText;
Synthesize it in the .m file:
#synthesize someText;
In the first view controller's segue method:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
NSLog (#"%#", [segue identifier]);
if ([[segue identifier] isEqualToString:#"F2S"])
{
// Get reference to the destination view controller
SecondViewController *gvc = [segue destinationViewController];
gvc.someText = **YOUR TEXT HERE** ; //this should set the value in the second view controller
}
}
If the passed value is not a string, change accordingly.
Here is the sequence of events happening in your code:
The segue object is created. Source and destination view controllers are set on the segue, causing the second view controller to be loaded.
-viewDidLoad: is called on the second view controller.
-prepareForSegue: is called on the first view controller.
-viewWillAppear: and -viewDidAppear: are called on the second view controller.
-viewDidLoad: is called before guessWord is configured in -prepareForSegue:. Try -viewWillAppear: or -viewDidAppear: instead when logging guessWord.
Related
So I know that if there is a segue which is setup and activated through the storyboard, one can use the prepareForSegue method to pass data to the destination view controller.
I'm wondering if there is a way to do this if one uses the performSegueWithIdentifier method? It seems the prepareForSegue method is only called if the segue is activated with the storyboard, not with performSegue.
One particular problem is that I can't access the UIStoryboardSegue (it is not an argument in performSegue as it is in prepareForSegue), and therefore can't access the destination VC either.
Answer is here in StackOverflow.
How to pass prepareForSegue: an object
// When any of 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];
}
}
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;
}
I have used prepareForSegue successfully, which I have managed to pass variables though. I am trying to now pass a NSNumber through the reverse of the segue but prepareForSegue is not getting called. To get back to my previous VC I am using:
[self.navigationController popViewControllerAnimated:YES];
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"ShowImages"]) {
DiaryViewController *photoNumber = [segue destinationViewController];
photoNumber.deleteObject = self.rowTodelete;
}
Is there something I can add to make the prepareForSegue to work in reverse. Or would I need to access my NSNumber from the different class somehow?
If you set up an unwind segue, you can get the UIViewController that is causing the unwind.
Check out this answer here about Unwind Segues.
Once you actually set up the unwind segue structure, here's some sample unwind segue code:
- (IBAction)unwindToRed:(UIStoryboardSegue *)unwindSegue {
UIViewController* sourceViewController = unwindSegue.sourceViewController;
if ([sourceViewController isKindOfClass:[DiaryViewController class]] {
DiaryViewController *photoNumber = (DiaryViewController *)sourceViewController;
NSNumber *deleteObject = photoNumber.deleteObject;
}
}
You could also use the Delegate-Pattern for it.
Just set the current Controller as the Delegate of the destination controller and create a protocol that defines which method the delegate should be implement.
Then you can pass any parameters you want back to the source Viewcontroller if your destination controller gets dismissed.
// Source Controller (which is also the delegate of the destination-controller)
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
SomeController * a = segue.destinationController;
a.delegate = self;
}
// Delegate Method
-(void)viewControllerGotDismissed:(NSNumber*)test{
NSlog(#"TEST:%#",test);
}
// Destination Controller
#protocol SomeProtocol
-(void)viewControllerGotDismissed:(NSNumber*)test;
#end
// Destination Controller
-(void)viewWillDisappear {
// ....
[self.delegate viewControllerGotDismissed:#1337]; // Pass the value to the source Controller
}
#end
Another method that could work for you is assigning a completion block to run when the presented view is dismissed. For example, if A presents B with a segue, then set a completion block when you initially segue to B. When B is about to be dismissed, run the completion block.
In ViewControllerB.h
#property (nonatomic, strong) void (^onDismiss)(UIViewController *sender, NSNumber *aNumber);
In ViewControllerB.m
// execute the block right before A is presented again
- (void)viewWillDisappear:(BOOL)animated {
self.onDismiss(self, aNumberToPassBack); // Run the block
}
In ViewControllerA.h
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"SegueToB"]) {
ViewControllerB *vcb = [segue destinationViewController];
vcb.onDismiss = ^(UIViewController *sender, NSNumber *aNumber) {
self.aNumber = aNumber;
// ... update your views if needed
};
}
}
I am having two view controllers 'FirstViewController' and 'SecondViewController'. From first view controller it will take input from a text field ,process it and display accordingly in the second view. But I am having a problem while setting label value directly.
#interface SecondViewController : UIViewController
{
NSString *numPlate;
IBOutlet UILabel *output;
};
#property(strong,nonatomic) NSString *numPlate;
#property(strong,nonatomic) IBOutlet UILabel *output;
#end
The main file for FirstViewController.m with prepare for segue is as
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([[segue identifier] isEqualToString:#"Change"])
{
SecondViewController *svc = (SecondViewController *)[segue destinationViewController];
svc.numPlate = input.text;
NumberPlate *numPlate=[[NumberPlate alloc]init];
[numPlate setPlate:input.text];
NSInteger flag=[numPlate checkValidity];
if(flag==0)
{
svc.output.text =#"Invalid License";
}
else
if([numPlate getArea]==NULL||[numPlate getRegOffice]==NULL)
{
svc.output.text =#"Data not found";
}
else
{
svc.output.text =#"VALID License";
}
}
}
But when the action is performed its not working.The label is not changing.
When i used svc.numPlate instead of svc.output.text and in the SecondViewController viewDidLoad method and i used
- (void)viewDidLoad
{
[super viewDidLoad];
output.text=numPlate;
}
Everything is fine with this. Whats wrong in first method??
You will not be able to assign value directly to UILabel of second VC as view is not yet loaded into view hierarchy at this point.
So view cannot render the value assigned prior to it.
On the other hand, holding value in NSString and assigning same on viewDidLoad is working as now your view is in view hierarchy and loaded into memory.
At the time when you push SecondViewController, the SecondViewController's view hasn't been loaded yet, so you can't access its views. You need to create NSString properties in SecondViewController and pass a string to SecondViewController' NSString Object. Then in SecondViewController's viewDidLoad method, use those properties to populate the labels (which will have been loaded by the time viewDidLoad runs).
The initialisation of controller is different and presentation of its view is different process even if the viewController has been initialise its view will not because pushing the controller has not performed and controller dont know he need to load the view.. so we pass the data to controller and it load when view appears... like below code
#interface SecondViewController : UIViewController{
NSString *strMessage;
}
#property(nonatomic,retain) NSString *strMessage;
#end
SecondViewController.m
#synthesize strMessage;
- (void)viewDidLoad {
Nslog(#"%#",strMessage);
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([[segue identifier] isEqualToString:#"Change"])
{
SecondViewController *svc = (SecondViewController *)[segue destinationViewController];
NSString *message = [NSString stringWithFormat:#"Check out %#", nameLb.text];
svc.strMessage=message;
}
I currently have two view controllers and I linked them up via storyboard segue(navigation controller). When the user presses a button on the first view, the screen goes to the second view. In the second view, there are text fields so that the user can edit the detailed information. When I press the back navigation button, how can I pass that detailed information from the second view controller back to the first view controller?
I use this code to send data from the first view controller to the second view controller
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
SettingsViewController *settingsViewController = [segue sourceViewController];
[settingsViewController setAddressString:[self addressString]];
NSLog(#"Settings address string of SettingsViewController to: %#", [self addressString]);
}
The only way I can think of right now of passing the data from the second view controller to the first view controller is to override the viewWillDisappear method of the second view controller. But is there a way that works by using the segue method? And what is the recommended way of doing this?
You could use delegation.
In your second view controller header file you'll have to create a delegate method.
#protocol SettingsDelegate <NSObject>
- (void)userHasCompletedSettings:(NSArray *)userSettings;
#end
#interface SettingsViewController : UIViewController
#property id<SettingsDelegate>delegate;
// Any other properties you have
#end
In your first view controller when calling your segue you set the delegate to self.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
SettingsViewController *settingsViewController = [segue sourceViewController];
[settingsViewController setAddressString:[self addressString]];
NSLog(#"Settings address string of SettingsViewController to: %#", [self addressString]);
settingsViewController.delegate = self;
}
In your second view controller you need to call the method. You can implement your own Back button so that you can set up an IBAction to call your delegate method.
- (IBAction)backButtonPressed:(id)sender
{
// Package up your settings details in the array
[self userHasCompletedSettings:arrayOfMySettings];
[self dismissViewControllerAnimated:YES completion:nil];
}
You also need to set up the method for the backButtonPressed action to call on the first view controller.
-(void)userHasCompletedSettings:(NSArray *)userSettings
{
// Do what you need to do with the settings.
}
You can pass the detail controller a reference to the master view controller (i.e. self), and let it call methods to set the results.
For example, you can do this:
#interface MasterController : UIViewController
-(void)updateAddressString:(NSString*) address;
#end
#interface DetailController : UIViewController
-(void)setAddressString:(NSString*) address;
#property (nonatomic, readwrite) MasterController *master;
#end
Now you can write this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
SettingsViewController *settingsViewController = [segue sourceViewController];
[settingsViewController setAddressString:[self addressString]];
[settingsViewController setMaster:self];
NSLog(#"Settings address string of SettingsViewController to: %#", [self addressString]);
}
When the DetailController needs to update the address in the master, it does this:
[_master updateAddressString:updatedAddress];
You can create a class which represents your model object with properties that correspond to fields in SettingsViewController.
You create it and pass to your SettingsViewController in prepareForSegue method and assign it to property/ivar of the current viewController. So you have a model object instance shared between two viewControllers. When you enter information into fields - assign it to your custom model object properties.
Your first viewContoller can get information from properties of the shared model object.