Ok, this is really bugging me and I am sure the solution is simple... I am unable to set my ViewController's property variables from another class (SeverConnect.m), which I have declared and synthesized properly in my ViewController's .h/.m files:
ServerConnect.h:
#import <Foundation/Foundation.h>
#import "ViewController.h"
#import "Contact.h"
#class ViewController;
#interface ServerConnect : NSObject
{
Contact *newContact;
NSString *codeRawContent;
NSMutableArray *contactListCopy;
... //Other variables declared here, but not shown in order to save space
Inside ServerConnect.m:
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
NSLog(#"parserDidFinish");
newContact = [[Contact alloc] initWithCodeInfo:(NSString *)codeInfo
contactName:(NSString *)completeName
contactImage:(UIImage *)profileImage
contactWebSite:(NSString *)codeRawContent];
[contactListCopy insertObject:newContact atIndex:0];
[ViewController setContactList:contactListCopy]; //Automatic Reference Counting Error Occurs Here: "No known class method for selector 'setContactList:'"
}
As I mentioned above, I have declared and synthesized the property variable, "contactList", in my ViewController's .h/.m files (with no errors):
#property (nonatomic, retain) NSMutableArray *contactList; //In ViewController's .h file
#synthesize contactList; //In ViewController's .m file
Can someone tell me what I am doing wrong? Thanks in advance for any help you can provide!
you are trying to access an instance property on a class:
[ViewController setContactList:contactListCopy];
you need to first create an instance of the ViewController class, and then set its property. Something like this:
ViewController *viewController = [[ViewController alloc] init];
[viewController setContactList:contactListCopy];
In this line of code:
[ViewController setContactList:contactListCopy];
you should be using a variable of type ViewController. The way you are using it, it should be a class method, not a property.
Write something like:
ViewController *viewController = [[ViewController alloc] init];
[viewController setContactList:contactListCopy];
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'm setting a string in a view controller called ViewController and trying to access it somewhere else. This is the code:
ViewController.h
NSString *string;
...
#property (retain) NSString *string;
ViewController.m
#synthesize string;
...
-(void)viewDidLoad {
...
string = #"Test";
}
OtherViewController.m
#import "ViewController.h"
...
-(void)viewDidLoad {
ViewController *vc;
vc = [[ViewController alloc] init];
NSLog(#"String: %#", vc.string);
}
However, the log is showing: String: (null). What am I doing incorrectly? Thanks.
The viewDidLoad of ViewController is only called when the view is loaded. The view is lazily loaded when required e.g. when a call to vc.view is made.
I'm not sure what you are trying to achieve but this certainly seems like a code smell to me.
As #Fscheidl points out you are creating a new instance and not accessing an existing instance so this may add to your problem. I still believe your main issue is that you assume viewDidLoad is being called just by creating the viewController, which is not the case
edit : it doesn't necessarily need to be an NSObject class, if you want to, you could also do this on your viewController class, just be sure to also include
-(id)init
on your header
---- end of edit
if you're trying to make a class that's accessible to another view controller, why not try NSObject instead of view controller (considering you only need to take that string value)
for instance, lets call that viewController class "global" class
so at global.h, you put up
#import <Foundation/Foundation.h>
#interface GlobalVar : NSObject
#property (nonatomic, strong) NSString *myString;
-(id)init;
#end
and then, at global.m you put up
#import "GlobalVar.h"
#implementation GlobalVar
#synthesize myString;
-(id)init
{
self = [super init];
if(self)
{
myString = [[NSString alloc]initWithFormat:#"the String"];
}
return self;
}
#end
after this, everytime you need to access the "myString" object that contained in global class, you could put up
at header :
#import "GlobalVar.h"
...
...
#property (nonatomic, strong) GlobalVar *globalVar;
at implementation file :
#synthesize globalVar;
...
...
self.globalVar = [[GlobalVar alloc]init];
NSString *theString = globalVar.myString;
NSLog(#"content of my string is : %#",theString);
there you go ;)
You do create a new instance of ViewController by calling [[ViewController alloc] init]; This instance hasn't had string even set. You have to access that exact instance of ViewController.
If you create the instance of OtherViewController directly from ViewController, you can add the following to OtherViewController.h:
#import "ViewController.h"
#property (nonatomic, retain) ViewController *previousViewController
When creating the OtherViewController, you can then set:
//alloc and init instance of OtherViewController
myOtherViewController.previousViewController = self;
In your viewDidLoad: method, you can then access your string as follows:
NSLog(#"String: %#", previousViewController.string);
I'm trying to pass a string through two views on an iPhone app. On my second view that I want to recover the string in the .h i have:
#import <UIKit/UIKit.h>
#import "MBProgressHUD.h"
#import "RootViewController.h"
#interface PromotionViewController : UITableViewController {
NSString *currentCat;
}
#property (nonatomic, retain) NSString *currentCat;
#end
And in the .m i have:
#synthesize currentCat;
However, in the first view controller when I try and set that variable I get a not found error:
PromotionViewController *loadXML = [[PromotionViewController alloc] initWithNibName:#"PromotionViewController" bundle:nil];
[self.navigationController pushViewController:loadXML animated:YES];
[PromotionViewController currentCat: #"Test"];
That third line gives me a: Class method +currentCat not found
What am i doing wrong?
Tom,
The issue in your code appears that you are trying to set the string using a static method call to the class. This would work if you implemented a static method named currentCat:
I don't think this is what your want.
See below on how to correct your issue.
[PromotionViewController currentCat:#"Test"];
//This will not work as it is calling the class itself not an instance of it.
[loadXml setCurrentCat:#"Test"];
//This will work. Keep in mind if you are going to call the objective-c
//synthesize setting directly you will need to capitalize the first letter
//of your instance variable name and add "set" to the front as I've done.
//Alternatively in objective-c 2.0 you can also use
//the setter method with the . notation
loadXml.currentCat = #"Test";
//This will work too
You need to get the string like this, as it's a property and not a method:
NSString* myString = controller.currentCat; // where controller is an instance of PromotionViewController
You need to do:
loadXML.currentCat = #"Test";
PromotionViewController *loadXML = [[PromotionViewController alloc] initWithNibName:#"PromotionViewController" bundle:nil];
[loadXML setCurrentCat: #"Test"];
[self.navigationController pushViewController:loadXML animated:YES];
That should do it.
How can I get access to a NSMutableArray that has been hydrated in different Class?
There is my sample code:
Class1.h : I have an iVar NSMutableArray *anArray;
And I #synthesize anArray; it in Class1.m
In the RootViewController I import the Class1.h and addd #Class "Class1";
The in the interface I add the Class1 *aClass1; in the RootViewController.m I #synthesize it and in the ViewWillAppear
aClass1 = [[Class1 alloc] init];
aClass1.anArray = [[NSMutableArray alloc] initWithObjects: #"string1",#"string2",nil];
NSLog(#"aClass1.anArray is Class1 %#",aClass1.anArray); // It works as I expected
Now in the new class I call it DetailsViewController
Same as the RootViewController.h I imported the .h and #class "Class1";.
Also in the DetailsViewController.m I have imported the "Class1.h"
So now in the DetailsViewController I try to do this in the viewWillAppear
NSLog(#"aClass1.anArray in DetailsViewController %#",aClass1.anArray); // PROBLEM: It comes back as null
I have added this sample project in this address: http://www.epicdesign.com.au/test2.zip
You just forgot to set the aClass1 ivar of the details view controller before you pushed it onto the navigation controller. Here is the code that should be in your didSelectRowAtIndexPath method:
DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
// ...
// Pass the selected object to the new view controller.
detailViewController.aClass1 = aClass1; // this line was added
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
Once you add the line that I added above, your array will now show up correctly in the detail view controller.
You're accessing a property that you haven't declared yet in the Class1.h, so you must add there:
#property (nonatomic, copy) NSMutableArray *anArray;
Since it should work, I prefer not to pass any NSMutableArray as parameter. You should better declare a NSArray property in Class1.h to pass it to your methods and then mutableCopy it where you want to make modifications to the array (only inside the methods). And remember that mutableCopy and copy increase the retain count of your array, so you must release it when you are done.
I'm trying to set a variable in another view.
I'm in a view which I have named ProgramViewController and from here I would like to set a variable named bands in MyViewController.
I thought it would be as simple as
MyViewController *myViewController = [[MyViewController alloc] init];
myViewController.bands = #"hello world";
[myViewController release];
And in the header of MyViewController:
#interface MyViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
NSString *bands;
}
#property (nonatomic, retain) NSString *bands;
That does not work, though.
Can anyone please tell me what I am doing wrong?
EDIT:
I synthesize bands in MyViewController:
#synthesize pageNumberLabel, tableProgram, bands;
But when trying to print it with NSLog in the viewDidLoad of MyViewController I get (null)
NSLog(#"%#", bands);
You need to synthesize the bands variable in MyViewController.m
#synthesize bands;
A variable needs to be synthesize in order to use it as a public property outsize of a class in Objective-C
I solved this in another way. I managed to load the data in MyViewController instead. I was dealing with a page controller and had to populate a UITableView but had troubles loading the data.
This is solved in a completely other way now.