I have a NSString member variable declared in the header file of the view controller:
#interface MyApprViewController : UIViewController {
NSString *var;
...
}
#property (retain) NSString *var;
...
-(IBAction)buttonPressed: (id)sender;
Inside the implementation, I use #synthesize var and try to use that var from within the implementation of the buttonPressed method, but it does not work properly and I assume it is because var was never initialized. Where can I initialize this variable? I do not want to do it inside the method; I want to do it once of course, because I will keep appending text to it:
-(IBAction)buttonPressed: (id)sender {
NSString *input = ((UIButton *)sender).currentTitle;
var = [var stringByAppendingString:input];
textField.text = var;
}
[input release];
}
I tried overriding the init method inside the view controller class, but it never gets called (maybe because there is no explicit initialization of the view controller class?) So, where should I initialize var so that I can use it inside the view controller class (inside the buttonPressed method)?
Thanks,
Mihai
There are several places to initialize:
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle
This is the designated initializer. You said you overloaded "init" which is not the designated initializer for UIViewController.
- (void)awakeFromNib
If your view controller is itself inside of a parent NIB, this method is called once the parent NIB is fully loaded and the parent NIB's outlets have all been wired.
- (void)viewDidLoad
If your view controller has a NIB, this is called when its NIB has been loaded.
- (void)loadView
If your view controller doesn't have a NIB, this is called when its view is first requested.
The best place would be inside your viewDidLoad or any init method you use. If you have neither, just add a method -(void)viewDidLoad to your UIViewController.
Of course this will not work, stringByAppendingString is an instance method, and var is never allocated. The best way to initialize ,if you have a nib file (as this example appera to have) is on viewDidLoad, but check before initialize if is allready nil, to avoid every time this method is called a new object is allocated. finally remember release
Related
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
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.
if you have the reference from the object view controller you can just access by the property from your attribute.
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.
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.
i have 2 classes . in my first class i have one label. now i have to give input for that label from my second class.
here is my code.
IBOutlet UILabel *label1;
#property(nonatomic, retain) IBOutlet UILabel *label1;
#synthesize label1;
I call this label like this.
I import my class1 and create object like classone.
I checked(NSLog print)class and that method will be called but that input won't come.i checked that label its also connected to my class.because i give same input in my viewDidLoad that time its working fine.
NSString *ram= #":13123123312";
classone.label1.text= ram;
guide me where i'm doing wrong.
Setting values of previous views is trickier than this. What it the view has been removed by the OS under memory pressure?
The proper way of setting these values is to use the MVC pattern that is used throughout the Cocoa frameworks. Your second view controller sets a property of the previous view controller. And when the previous view needs to be shown, it takes its value from this property.
The usual way to correctly hook up a view controller to talk back to a another view controller lower in the stack is to use a delegate protocol.
I wrote an example of this, DelegationExample,a while ago which shows how a textfield in the first view is populated by a textfield's value in the second view controller using a delegate protocol. You might find it useful to see how I have done this as an example.
Update
I've updated the link to a new project for iOS6 with ARC and Storyboards
Take one NSString variable in AppDelegate class and synthesize it properly. And store the value of the second class's variable to that like:
appDelegate.strLbl = [NSString stringWithformat:#"%#",strVal];
and then copy that value to the label in first class like:
lblVal.text = [NSString stringWithformat:#"%#",appDelegate.strLbl];
Hope that helps you. Thanks.
Actually you should have the reference of the first class in the second class. You should not allocate a new instance. If you create new instance, then the instance for which you have set the label value is different from the actual one which you will see on clicking back.
I guess you got this.
Aadhira was right, when u create a new instance of class1 in class2 its wrong,
You have to get the original instance of class1, this can be achieved by creating a static function which returns current instance of class1, as shown below
static classone* sInstance;
#implementation classone
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization.
}
sInstance = self;
return self;
}
+(classone*) getInstance {
// NSAssert (sInstance!=nil, #"classone:getInstance: called when singleton was not initialized!");
return sInstance;
}
I have 2 view controllers now, And it both got tableviews.
When I choose a row in the second tableview (Using didSelectRowAtIndexPath),
and I want to pass the Information I got in the second View to the first View,
I tried to use delegate&protocol, but don't know why, It didn't work.
And I tried to use class method inside the first class, when I got variable in sencond View,
Call the class method inside the first class. The variable successfully pass to first View,
but when I want to set the Lable's text, it still failed..
Can somebody teach me how to do? thanks!
My protocol&delegate.
This is the second view.
#protocol CategoriesViewControllerDelegate;
#interface CategoriesViewController : UIViewController {
TableViewNewAppDelegate *appDelegate;
id <CategoriesViewControllerDelegate> delegate;
}
#property (nonatomic, assign) id <CategoriesViewControllerDelegate> delegate;
#end
#protocol CategoriesViewControllerDelegate <NSObject>
-(void)backstring:(NSString *)String;
#end
In the .m file , synthesize it
#implementation CategoriesViewController
#synthesize delegate;
didSelectRowAtindexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
CategoryData *CateObj = [appDelegate.CateArray objectAtIndex:indexPath.row];
NSString *Strings = [NSString stringWithString:CateObj.CateTitle];
[delegate backstring:Strings];
[self.parentViewController dismissModalViewControllerAnimated:YES];
}
In the first view controller .h file.
#import "CategoriesViewController.h"
#interface DataController : UIViewController <CategoriesViewControllerDelegate>{
.m file
-(void)backstring:(NSString *)String {
NSLog(#"%#",String);
jCateField.text = String;
}
This is how I do my protocol+delegate. Are there something wrong?
btw, I created a Class method in the first view controller, and use the Class method in the sencond view controller, it succesfully pass variable to first view controller.
But the problem is, I can't set my Label's text inside my Class method, even calling Instance method to set text. Is there any way to solve this problem?
The code you provided seems to be correct. In your case you must set :
#property (nonatomic, assign) id <CategoriesViewControllerDelegate> delegate;
correctly to point to the first view controller which conforms to the protocol you defined :
#import "CategoriesViewController.h"
#interface DataController : UIViewController <CategoriesViewControllerDelegate>{
So it seems that you pushed a CategoriesViewController onto a first DataController, you probably missed to do so just before.
// self is the first view controller
// [myCategoriesViewController setDelegate:self]; old fashion
myCategoriesViewController.delegate = self;
[self presentModalViewController:myCategoriesViewController animated:YES];
This can probably solve your issue. Hope this helps.
Also consider let the first controller dismiss the second.
Here is a link to Apple's documentation.
You could just pass the information straight on to your second view controller;
SecondViewController.h
#interface SecondViewController
{
Information *info;
}
#property (nonatomic, retain) Information *info;
#end
SecondViewController.m
#implementation SecondViewController
#synthesize info;
...
#end
And in your didSelectRowAtIndexPath method;
SecondViewController *controller = [[SecondViewController alloc] initWithNibNamed:#"SecondViewController" bundle:nil];
[controller setInfo:YOUR_INFO_OBJECT];
[self.navigationController pushViewController:controller animated:YES];
[controller release];
Import second view controller header file in the first view controller implementation file. Import first view controller header file in second view controller header file.
Create the property (text/label/whatever) in the first view controller.
Create the property of first view controller in the second view controller.
Create the second view controller instance, set the first view controller property to what you need, push controller to the navigation controller. In the second view controller change whatever you want in the first view controller. Instance methods allowed. Do not forget to release first view controller.
Delegate pattern works in that way too.
View controllers are objects. Objects can have methods that can be called from other objects, and they can have instance variables. ("Delegate" is just a fancy term for this.)
There's no inherent reason why passing data between your view controllers should be hard or complicated, so long as the caller has the address of the callee. (And whether or not a given VC has an XIB is irrelevant.)
It sounds like your real problem is not knowing what to do with the data once it's been passed to the callee.
Stupid question: Is "jCateField" actually connected to the label you want to change, or is it nil? If you created the label from code (since you don't have an XIB), you will need to have stored the created label's address into "jCateField" during the view creation.
Can you post the code for as to ho you are displaying the contents when you come back to 1 st view controller.As here if the log gives you proper value then the issue is with the connection (if taken through iboutlet) or with addsubview .
Do you get nil in label or no value (label is hidden).
I am currently creating my first app for a personal project and I'm having trouble modifying a UILabel's properties when MyViewController is loaded.
From other tutorials, I see that when the nib for my app is unarchived, the initWithCoder app is called:
#synthesize tipText; //references the UILabel i created in my nib file
- (id)initWithCoder:(NSCoder *)coder {
if (self = [super initWithCoder:coder]) {
self.tipText.layer.cornerRadius = 8; //the UILabel property i wish to modify
}
return self;
}
However, when the above code runs, the tipText is not bound to any memory yet.
Where should i place my self.tipText.layer.cornerRadius code such that tipText is initialized and before the UILabel is displayed in my UI?
You want to do this in -[UIViewController viewDidLoad]
you should implement the following method
-(void)awakeFromNib
and make changes there. This method is called on objects after they are unfrozen from a nib file.
I have an NSMutableArray in my MainViewController classes.. I added 10 Objects to NSMutableArray.When i Click subview button in my MainViewController classes, I push SubviewController (UIViewController)classes.... In subviewcontroller classes i want to use MainViewController Values of NSMutableArray. And also i Want to add or remove objects from that NSMutableArray...
My aim is I want to use the NSMutableArray Values to all UIViewController classes to my project with an same name of the variable.
If I understand you right - you want to access the NSMutableArray in MainViewController from all your (subview) controllers?
You can store the handle to your MainViewController in all you subviews and access the array using that handle.
I think better idea would be move the data to some globally accessible instance (e.g. to ApplicationDelegate class or wrap it into singleton class)
What you want to do is add a Cocoa property in your main view controller that references the NSMutableArray instance which you instantiate and populate with elements.
In the header:
#interface MainViewController : UIViewController {
NSMutableArray *myMutableArray;
}
#property (nonatomic, retain) NSMutableArray *myMutableArray;
#end
In the implementation, add the #synthesize directive and remember to release the array in -dealloc:
#implementation MainViewController
#synthesize myMutableArray;
...
- (void) dealloc {
[myMutableArray release];
[super dealloc];
}
#end
You also want to add this property to view controllers that are subordinate to the main view controller, in the exact same way.
In your main view controller, when you are ready to push the subordinate view controller, you set the subordinate view controller's property accordingly:
- (void) pushSubordinateViewController {
SubordinateViewController *subVC = [[SubordinateViewController alloc] initWithNibName:#"SubordinateViewController" bundle:nil];
subVC.myMutableArray = self.myMutableArray; // this sets the sub view controller's mutable array property
[self.navigationController pushViewController:subVC animated:YES];
[subVC release];
}
Likewise in your subordinate view controller, it will need to set its subordinate's mutable array property accordingly, when it pushes its own view controller.
By setting references in this way, each view controller is pointed at the same mutable array, containing the desired elements.
To use the array, just call self.myMutableArray, e.g. [self.myMutableArray addObject:object].