I have a viewController that has a button which, when clicked, dynamically creates a reference to another viewController class, and in the process sets the parameters for that viewController as well. I do this inside a for loop as follows:
-(void) clickOnButton:(id)sender {
for (PersonObject *checkPerson in [DataModel sharedInstance].personList) {
if (((UIControl*)sender).tag == checkPerson.personID) {
ParentViewController *parentView = [[NSClassFromString(checkPerson.childViewController) alloc] init];
parentView.personName = checkPerson.name;
NSLog(parentView.personName);
[self.navigationController pushViewController:parentView animated:YES];
}
}
}
In the viewController that gets created and to which the user is sent to, I have the following code in my viewDidLoad method:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSLog(@"Hello %@", personName);
UILabel *title = [[UILabel alloc] initWithFrame:CGRectMake(0, 10, 150, 35)];
[title setCenter:CGPointMake(self.view.frame.size.width/2, 27)];
[title setBackgroundColor:[UIColor clearColor]];
[title setTextAlignment:NSTextAlignmentCenter];
[title setFont:[UIFont boldSystemFontOfSize:15]];
[title setText:personName];
[self.view addSubview:title];
}
When I run my code, the first viewController gives me the correct output to the NSLog of the personName parameter, however, the NSLog() inside the method viewDidLoad in the second viewController statement shows that my value for personName is nil, and nothing shows up as my title for the viewController.
The parameter personName is of type NSString and is found in both the parent viewController class, as well as the child viewController classes (there are several viewController classes that are extending this one parent). How do I dynamically create the child viewController object as well as have it capture the correct parameter value that is being sent to it using the parent viewController?
A common mistake is to have an interface in the view controller to which you’re transitioning to have an interface like:
and then an implementation that either does not explicitly synthesize
personNameor one that has a@synthesizestatement like:Note, if you don’t have an explicitly declared
@synthesizestatement, it will automatically synthesizepersonNamelike the above statement.This rather innocuous bit of code is problematic, because you’ll end up with two instance variables, one called
personNameand another, which is synthesized for you, which is called_personName.What you really should do is eliminate the explicitly declared ivar, thus the
@interfacewould look like:And then either omit the
@synthesizestatement altogether or have one that looks like:And then, your code can either refer to the property via its accessors, e.g.
Or you can use the instance variable (the ivar):
(As an aside, it’s generally advisable to use the accessors (e.g.
self.personName) when setting properties. The only time you really must use the ivar (e.g._personName) is in the initializer methods and dealloc.)But, bottom line, don’t explicitly define an instance variable, let the compiler synthesize it for you, eliminating this sort of problem. And it’s advisable to synthesize the ivar with the leading underscore, to minimize accidental use of the ivar when you really intended to use the property’s accessor methods.
See Practical Memory Management in the Advanced Memory Management Programming Guide for more information.