IBOutlet instances are (null) after loading from NIB
Asked Answered
G

5

19

I am working on an iPhone app and am getting (null) references to IBOutlet fields in my controller. I have a UIViewController subclass that is set as the File's Owner in my XIB. I have a set of UI elements that are wired into the controller. After loading from NIB and attempting to set properties on those UI elements, I find that they are (null). To clarify, some code:

ExpandSearchPageController.h:

@interface ExpandSearchPageController : UIViewController
{
  IBOutlet UITextView * completeMessageView;
}

-(void)checkTextField;

@property (nonatomic, retain) IBOutlet UITextView * completeMessageView;

ExpandSearchPageController.m:

@implementation ExpandSearchPageController

@synthesize completeMessageView;

-(void)checkTextField
{
  NSLog(@"text field: %@",completeMessageView);
}

ExpandSearchPageController is set as the File's Owner for ExpandSearchPage.xib. ExpandSearchPage.xib's UITextView is wired to the completeMessageView.

When I call

ExpandSearchPageController * searchExpanderPage = [[ExpandSearchPageController alloc] initWithNibName:@"ExpandSearchPage" bundle:[NSBundle mainBundle]];

[searchExpanderPage checkTextField];

the result is

"text field: (null)"
Germann answered 11/8, 2009 at 1:9 Comment(0)
G
50

I guess asking the question after looking at the problem for over an hour led me to figure it out:

I just changed my code to check the text box AFTER displaying the view... now everything is instantiated.

Imagine that: the UI elements aren't instantiated until you display them!

Germann answered 11/8, 2009 at 1:16 Comment(2)
Another point of interest which caught me. When presenting a view controller modally with presentViewController:animated:completion:, all the IBOutlets will be nil until the view appears (what you discovered). So you'll need to access them via the completion block, which gets called when viewDidAppear is called on the modal.Zinfandel
This was helpful even now in 2024. The thing is that in Objective-C nils are mostly handled gracefully and in Swift... no. So you gotta explicitly know this thing that you might not have known when you go to Swift.Prison
C
5

This is the solution.

The IBOutlets aren't ready to use until the view controller finishes loading.

For example, if you want to set a UILabels text property, you would need to set a NSString on your controller first, and then set the labels text property in somewhere like viewDidLoad.

So in your firstViewController.m : (This is for storyboards, but same idea applies)

- (void)buttonPress:(id)sender {
   [self performSegueWithIdentifier:@"mySegue" sender:self];
}

- (void)prepareForSegue(UIStoryboardSegue *)segue sender:(id)sender {
   SecondViewController *secondViewController = [segue destinationViewController];
   secondViewController.stringForLabel = @"My Label String";
}

Then in the .h of your secondViewController:

@property (strong, nonatomic) IBOutlet UILabel *label;
@property (strong, nonatomic) NSString *stringForLabel;

Then we set the text property on the UILabel, in the viewDidLoad of secondViewController.m. By this stage, the IBOutlet has been created and is ready to go.

- (void)viewDidLoad {
   [super viewDidLoad];
   self.label.text = self.stringForLabel;
}
Cloyd answered 7/1, 2015 at 5:34 Comment(0)
A
3

Another potential cause of a null IBOutlet pointer is forgetting to save the xib file in Interface Builder after creating the outlet connection.

Afterclap answered 24/4, 2010 at 10:33 Comment(1)
I believe that was a problem in the earlier versions of XCode -- %-R did not automatically save. Now it does. Still +1 as something to watch out for.Dorran
O
0

Make sure the view property of your view controller (ie File's Owner in this case) is wired to the view in your xib. As your textField is almost certainly a subview of that, it's important to get that wired in too (and I don't think the nib will load properly without that being set).

Odds answered 11/8, 2009 at 1:14 Comment(0)
C
0

This is how I do it:

//in your view controller
-(void)setUp
{
    [self.cardView layoutIfNeeded];
    LearnCardPlainText *cardNib = [[[UINib nibWithNibName:@"LearnCardPlainText" bundle:nil] instantiateWithOwner:self options:nil] objectAtIndex:0];
    cardNib.frame = self.cardView.frame;
    [cardNib setUpWithPart:learnModel];
    [self.view addSubview:cardNib];
}
Cerebrovascular answered 13/6, 2016 at 10:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.