Im trying to pass data from a textfield in ViewController2 to a label in ViewController. It do not seem to work and i get no errors. What am i missing in my Segue?
ViewController2.h
#interface ViewController2 : UIViewController {
IBOutlet UITextField *HomeTeam;
}
ViewController2.m
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
[segue.identifier isEqualToString:#"HomeTeam"];
NSString *homeTeamText = HomeTeam.text;
ViewController *vc = [segue destinationViewController];
vc.HomeTeamString = homeTeamText;
}
ViewController.h
#property (weak, nonatomic) IBOutlet UILabel *HomeTeamLabel;
#property (weak, nonatomic) NSString *HomeTeamString;
ViewController.m
#synthesize HomeTeamString, HomeTeamLabel;
You're missing an if. Unless you've copied and pasted wrong...
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([segue.identifier isEqualToString:#"HomeTeam"]) {
NSString *homeTeamText = HomeTeam.text;
ViewController *vc = [segue destinationViewController];
vc.HomeTeamString = homeTeamText;
}
}
[segue.identifier isEqualToString:#"HomeTeam"] returns a BOOL that lets you know whether or not this is the segue that's being performed.
Even if this isn't actually causing a problem (in this example), you should be doing this anyway. I will update this answer as more information is given.
Also, be aware that in this particular code, you're setting an NSString property on the destination view controller. Not a label...
Assuming everything on the storyboard is correct, be sure to add the following to your viewDidLoad or viewWillAppear method:
HomeTeamLabel.text = HomeTeamString;
And for good measure, you may need to change HomeTeamString from weak to strong.
EDIT: After some researching... it seems that the HomeTeamString property in your destination view controller MUST be strong as opposed to weak. Leaving it as weak allows it to be released as soon as the prepareForSegue method ends (it doesn't have an owner between prepareForSegue ending and viewDidLoad in the destination view starting). Changing it to strong will fix the problem ensuring it will only be released if the destination view controller is released.
Please verify that, you set the identifier of the segue in storyboard.
In your case the identifier will be HomeTeam.
Related
Two properties:
#property (retain, nonatomic) NSString *drinkType;
#property (retain, nonatomic) NSString *wheelType;
When accessed from viewDidLoad as self.drinkType, etc, they hold the value I expect. However, when accessed from a public method
-(void)updateSentenceWithSelectedAromas:(NSMutableArray *)selectedAromas;
they are null. What is happening here?
The "selectedAromas" array is passed from another controller to this method.
ViewController *aromaVC = [[ViewController alloc] init];
[aromaVC updateSentenceWithSelectedAromas:selectedAromas];
ViewController.h
-(void)updateSentenceWithSelectedAromas:(NSMutableArray *)selectedAromas;
#property (retain, nonatomic) NSString *drinkType;
#property (retain, nonatomic) NSString *wheelType;
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// This is working
NSLog(#"The drink type is:%#", self.drinkType);
}
-(void)updateSentenceWithSelectedAromas:(NSMutableArray *)selectedAromas {
// This returns null
NSLog(#"The drink type is:%#", self.drinkType);
}
I think your missing quite a few things, which leads me to think that you're missing some basic understanding of variable scope in ObjectiveC, let's see if this helps you in some way:
First, your selectedAromas array has no relation whatsoever with drinkType and wheelType. So passing this array to the ViewController seems irrelevant.
Second, in your ViewController you're declaring your own drinkType and wheelType variables, so there's no way they will have the value of some other class or Controller.
You probably aren't setting your properties soon enough (init would be a good place). viewDidLoad is called much later in relation to the code you posted.
Okay, Michael Dautermann was absolutely right. The method updateSentenceWithSelectedAromas was in fact running in a separate instance of the view controller. To solve this problem I implemented a protocol listener with my method and set the delegate of the child controller to its parent using a segue.
Thank you everyone for all your help.
In case anyone stumbles upon this, here is what I did:
ViewController2.h
#protocol updateSentenceProtocol <NSObject>
//Send Data Back To ViewController
-(void)updateSentenceWithSelectedAromas:(NSMutableArray *)selectedAromas;
#end
#interface ViewController2 : UIViewController
// delegate so we can pass data to previous controller
#property(nonatomic,assign)id delegate;
#end
ViewController2.m
#synthesize delegate;
-(void)someMethod {
[delegate updateSentenceWithSelectedAromas:selectedAromas];
}
ViewController.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"viewController2Segue"])
{
// Get reference to the destination view controller
ViewController2 *vc = [segue destinationViewController];
vc.delegate = self;
}
}
-(void)updateSentenceWithSelectedAromas:(NSMutableArray *)selectedAromas {
// do stuff with array and properties as needed
}
Im trying to set a UIImageView from a segue, and for some reason the image is not getting set..
Heres the .h files of my class that subclassed a UIViewController
#interface PhotoDisplayViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIImageView *photoView;
-(void)setPhoto:(UIImage *)photo;
#end
and heres the setPhoto
-(void)setPhoto:(UIImage *)photo{
NSLog(#"PHOTO %#", photo);
_photoView.image = photo;
NSLog(#"MYPHOTO %#", _photoView.image);
}
when i call setPhoto from prepare for segue, i see this in the console
2012-12-16 13:26:22.129 TestApp[2183:907] PHOTO <UIImage: 0x1fd7cd80>
2012-12-16 13:26:22.130 TestApp[2183:907] MYPHOTO (null)
Why is this happening?
It looks like _photoView is probably nil. It may not be set when loading the nib. Make sure you've wired it up properly in IB. Or perhaps you are calling -setPhoto: before the view has loaded.
I would advise you to change the weak to strong and take a look on this link.
Objective-C - weak property - getter autoreleases (Automatic Reference Counting)
I think you called setPhoto: method as following. In this situation, first setPhoto: is called and after that viewDidLoad method is called in PhotoDisplayViewController. That's why photoView is nil. Actually viewDidLoad method should be called in PhotoDisplayViewController.So you should change the code slightly.
-(void)someActionMethod{
[self performSegueWithIdentifier:yourIdentifier sender:nil];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([[segue identifier] isEqualToString:yourIdentifier]) {
photoDisplayVC = [segue destinationViewController];//photoDisplayVC is a object of PhotoDisplayViewController
[photoDisplayVC setPhoto:imageObject];
}
The change Code: In this situation first viewDidLoad method is called and after that setPhoto: method is called in PhotoDisplayViewController. Then you will get image.
-(void)someActionMethod{
[self performSegueWithIdentifier:yourIdentifier sender:nil];
[photoDisplayVC setPhoto:imageObject];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([[segue identifier] isEqualToString:yourIdentifier]) {
photoDisplayVC = [segue destinationViewController];//photoDisplayVC is a object of PhotoDisplayViewController
}
I think it will be helpful to you.
I'm trying to have my app take a picture then pass the image onto another view for editing but I can't seem to figure out how to change views, how to add an "ID" to a view in the storyboard or how to pass data between views.
The communication between two UIViewControllers needs to be managed manually, however, if you are using storyboards to create your app, there's some things that you need to take into account.
Let's say you have FirstViewController and SecondViewController(Lets assume you have everything set up in your Storyboard). FirstViewController will pass a UIImage to SecondViewController and they will look something like this.
#interface FirstViewController : UIViewController
- (IBAction)transitionToNextViewController;
#property (retain, nonatomic) UIImage *image;
#end
#implementation FirstViewContoller
- (IBAction)transitionToNextViewController;
{
[self performSegueWithIdentifier:#"SegueIdentifier"];
}
#end
And:
#interface SecondViewController : UIViewController
#property (retain, nonatomic) UIImage *image;
#end
You are probably wondering how are you supposed to pass the image to the SecondViewController. Well, when using storyboards, your UIViewControllers will receive a call to their method prepareForSegue:sender: . All you have to do is set the image property for the second UIViewController there.
#implementation FirstViewController
- (IBAction)transitionToNextViewController;
{
[self performSegueWithIdentifier:#"SegueIdentifier"];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
SecondViewController *secondViewController = (SecondViewController *)segue.destinationViewController; // You have to cast it
secondViewController.image = self.image;
}
#end
and that's it. To better understand Storyboards please read the apple docs here.
For reference, I'm trying to learn Objective-C through the Stanford iTunes-U course. I wanted to update one property from the setter of another (they are inherently connected. Also, is that bad style?). The property I am trying to update is a UILabel, but it doesn't work like I thought.
This code is in one of my view controllers:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
[segue.destinationViewController setProgram:self.brain.program];
}
Naturally, this code calls the setter for the Program property of the incoming viewController. Here's that setter code:
-(void)setProgram:(id)program {
_program = program;
self.title = [CalculatorBrain descriptionOfProgram:program];
[self.graphview setNeedsDisplay];
self.testLabel.text = #"Trying to update your text!";
}
and the header file:
#import <UIKit/UIKit.h>
#interface GraphViewController : UIViewController
#property (nonatomic, strong) id program;
#property (weak, nonatomic) IBOutlet UILabel *testLabel;
#end
Now, when this code is run, as the segue happens, the new view DOES have its title changed (the self.title line works). However, the UILabel DOES NOT get updated. Furthermore, if I call the setter again say in viewDidLoad, it does change the UILabel. Is this because of self being updated? What's going on here?
In one of the lectures, the professor explains that outlets aren't set yet in prepareForSegue. This means testLabel is nil, and you're sending a message to nil (which is allowed and doesn't crash your app). To solve your problem, set the textLabel's text in viewDidLoad or viewWillAppear.
I believe this is "fixed" in iOS 6, but it won't be backwards compatible, so if you want to support iOS 5 still, you'll have to use viewDidLoad or viewWillAppear to update outlets (which I think is better to do anyway).
In my presenting view controller, I have the following prepareForSegue function
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([[segue identifier] isEqualToString:#"goToView2"]){
ViewController2 *controller2 = [segue destinationViewController];
controller2.multiplierStepper.value = 7.0;
controller2.randomString = #"string set from Scene 1";
}
}
In ViewController2 there is an outlet for my UIStepper's value and an NSString
#property (strong, nonatomic) IBOutlet UIStepper *multiplierStepper;
#property (strong, nonatomic) NSString *randomString;
In ViewController2.m viewDidLoad, I am testing the values set above by the presenting view controller
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"in viewDidLoad: self.multiplierStepper.value: %f", self.multiplierStepper.value);
NSLog(#"in viewDidLoad: randomstring: %#", self.randomString);
}
The console output works nicely for the NSString, but the UIStepper value always shows the initial value defined in the Interface Builder (1).
[10682:f803] in viewDidLoad: self.multiplierStepper.value: 1.000000
[10682:f803] in viewDidLoad: randomstring: string set from Scene 1
The answer is probably glaringly obvious, but I cannot figure out how to set the value of a stepper in my destination view controller from the presenting view controller.
Any ideas what I'm doing wrong?
Do not set directly the value of the UIStepper in the the prepareForSeque method , it will not work !
You have to declare a property that will contains the value and then set the value of the stepper in the viewDidLoad event of the second controller ...
First of all declare an additional property to your second view controller (ViewController2) header file :
#property (nonatomic) double stepperValue;
Then set the property value :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([[segue identifier] isEqualToString:#"goToView2"]){
ViewController2 *controller2 = [segue destinationViewController];
controller2.stepperValue = 7.0;
controller2.randomString = #"string set from Scene 1";
}
}
Then in the destination viewController (ViewController2) :
- (void)viewDidLoad
{
multiplierStepper.value = [self stepperValue];
}
Note
Bear in mind that the best thing for encapsulation would be declaring the IBOutlet as private member of the class, to avoid that a client of the class can access directly the IBOutlet; to make an IBOutlet private you have to declare it in a class extension in the .m file ...