2

The code is from Stanford CS193p. I added a NSLog to check it out. The label seems not being initialized. Any idea?

@interface AskerViewController() <UITextFieldDelegate>
@property (weak, nonatomic) IBOutlet UILabel *questionLabel;
@property (weak, nonatomic) NSString *question;
@end


@implementation AskerViewController
@synthesize questionLabel = _questionLabel;
@synthesize question = _question;


 - (void)setQuestion:(NSString *)question
{
    _question = question;
    self.questionLabel.text = question;
    NSLog(@"label is %@", self.questionLabel);
}

@end

The NSLog result is:

2012-07-31 01:56:45.177 Kitchen Sink[23931:f803] label is (null)
Cezar
  • 55,636
  • 19
  • 86
  • 87
Philip007
  • 3,190
  • 7
  • 46
  • 71

1 Answers1

8

You are probably setting the question string property before you are displaying the view controller, presumably in prepareForSegue:? At this point, the view has not loaded and the label property will still be nil.

You're doing the right thing by having a separate string property, you're just missing the step that you must also set the label's text in viewDidLoad - at this point your label has been instantiated from the storyboard and is ready to use.

If you're setting properties before viewDidLoad is called, the label being nil is expected. And if you're setting properties from prepareForSegue, the view won't have been loaded yet. A view controller won't load it's view and subviews until it needs to display them on screen, and this doesn't happen until the segue is being performed - and as you can guess, prepareForSegue is done before the segue is performed.

jrturton
  • 118,105
  • 32
  • 252
  • 268
  • Don't alloc/init a label if there is one in your storyboard. That's where your label will be coming from. If you're setting properties before viewDidLoad is called, the label being nil is expected. And if you're setting properties from prepareForSegue, the view won't have been loaded yet. A view controller won't load it's view and subviews until it needs to display them on screen, and this doesn't happen until the segue is being performed - and as you can guess, prepareForSegue is done before the segue is performed. This has turned into a long comment, I'm going to add it to my answer... – jrturton Jul 30 '12 at 20:26
  • I see. I put something like segue.destinationViewController.question in prepareForSegue, which calls setQuestion, which in turn try to access questionLabel, which is not loaded yet during segueing as a subview in the view hierarchy of the destination view controller. That's why NSLog returns null. – Philip007 Jul 30 '12 at 20:39
  • Exactly right. You should still keep that code in setQuestion, because you may set the question again while the view is still loaded, you just need that extra bit in viewDidLoad as well. – jrturton Jul 30 '12 at 20:42
  • Amazing! My thought is just on the same problem: what's the purpose of keeping the code `self.questionLabel.text = question; ` in setQuestion. What if I have no need to set the question again? Because logic flow is to authorize presenting view controller to ask question, which use prepareForSegue to send the question string to presented view controller. The segue sets up the presented controller. The label text gets set in viewDidLoad. I don't want the label is set in any other way. So, in terms of safety, should I just remove the code, hence the custom setter (setQuestion) all together? – Philip007 Jul 30 '12 at 21:16
  • If that's the way you'll always use it, then yes, that would be fine. – jrturton Jul 31 '12 at 05:47