fs_tigre
fs_tigre

Reputation: 10738

How to access values from a different UIViewController

How can I access the value from an inputField located in a second viewController?

The class name of the second view controller is SettingsViewController and the outlet name for the inputField is setRateInput.

I tried this but it didn't work…

double taxRateFromInput = [[self.settings.setRateInput text]doubleValue];

when I NSLog it comes out as The value is: (null)

Any idea what I'm doing wrong?

Here is the implementation file for the main viewController:

#import "SettingsViewController.h"

@interface ViewController ()

@property (strong, nonatomic) SettingsViewController * settings;

@end

@implementation ViewController

// lazy instantiation 
-( SettingsViewController *) settings
{
    if (_settings == nil) {
        _settings = [[SettingsViewController alloc]init];
    }
    return _settings;
}


- (IBAction)calculatePrice:(id)sender {


    double taxRateFromInput = [[self.settings.setRateInput text]doubleValue];

@end

Upvotes: 0

Views: 391

Answers (4)

Mohannad A. Hassan
Mohannad A. Hassan

Reputation: 1648

You instantiated a new SettingsViewController, but you didn't do anything to instantiate its textfield setRateInput. You can do it when you instantiate it:

_settings = [[SettingsViewController alloc]init];
_settings.setRateInput = [UITextField alloc] initWithFrame:someFrame]];

or, as a beter solution, instantiate the text field in -init of SettingsViewController

- init {
  if (self = [super init] {
    self.setRateInput = [UITextField alloc] initWithFrame:someFrame]];
  }
  return self;
}

If you use nib files, this would be a lot easier.

Note: setRateInput is a bad name for a property. Consider rateTextField instead.

Edit I forgot to add that you have to add the text field as a subview to its parent view.

So it will be like,

_settings = [[SettingsViewController alloc]init];
_settings.setRateInput = [[UITextField alloc] initWithFrame:someFrame] autorelease];
[_settings.view addSubView:_settings.setRateInput];

In this case, the setRateInput is retained by its super view. You're not using ARC, so you can call autorelease on your text field.

The better solution: Use - (void) loadView; inside SettingsViewController. Loading the view is the responsibility of the correspondent view controller.

- (void) loadView {
    self.setRateInput = [[UITextField alloc] initWithFrame:someFrame] autorelease];
    [self.view addSubView:_settings.setRateInput];
}

Edit: xib files and storyboards can help you out. Give these tutorials a try.

Upvotes: 1

Juan Munhoes Junior
Juan Munhoes Junior

Reputation: 895

if you have the reference from the object view controller you can just access by the property from your attribute.

Upvotes: 1

Mario
Mario

Reputation: 4520

You are on the right track, also well done with your lazy instantiation (as a demonstration that you grasped the concept, I mean).

But note, that outlets don't get connected until viewDidLoad is called. So if you just alloc/init your viewController (lazily), the outlet to your textfield is pointing to nil. The outlet doesnt get connected until your controller's view property is accessed, ie the view is displayed.

What you could do is give the settings viewController a handle to your calculating viewController and let it set a public property on the calculating viewController that represents the rate. This is a common pattern - delegation - where one viewController (settingsViewcontroller) calls a method on its delegate (calculating viewController).

You wouldn't need the settingsViewcontroller property in your calculating viewController then, but just instantiate a new settings viewController every time you want it to be brought up, giving it a reference to your calculating viewController.

Another possibility - maybe even better - is to define a model object that does calculation and takes care of the rate it needs to calculate. Then you could give your settingsViewcontroller a reference to that model object (probably instantiated in your other viewController), so that it can change the rate on it.

PS: also re think how you instantiate viewControllers generally. The designated initialiser is -initWithNibName:bundle: - so usually, you wouldn't just alloc/ -init them. If you use storyboards (you probably should!), use storyboard's -instantiateViewControllerWithIdentifier: or use the above mentioned designated initialiser.

Upvotes: 0

kgdesouz
kgdesouz

Reputation: 1996

In theory, you could create a global. Create a new class, call it something like taxRate (.h and .m)

In taxRate.h, add the following code:

#import <Foundation/Foundation.h>
@class MyTaxRate;

@interface TaxRate : NSObject {


}

@property (nonatomic, retain) double * taxRateFromInput;

+(TaxRate*)getInstance;

@end

Then, in your controller, put a "#import taxRate.h" in there. In your .m file, add the following:

#import "TaxRate.h"

@implementation TaxRate


@synthesize taxRateFromInput;

static TaxRate *instance =nil;  

+(TaxRate *)getInstance
{
    @synchronized(self)
    {
        if(instance==nil)
        {         
            instance= [TaxRate new];
        }
    }
    return instance;
}


@end

Note: This is extremely similar in structure to what I'm purposing.

Upvotes: 1

Related Questions