views:

73

answers:

2

I have a UIViewController that needs to set a few labels when it receives a new (object) value for one of its properties:

-(void)setCurrentEvent:(Event *)e {
    [currentEvent release];
    currentEvent = [e retain];
    self.dateLabel.text = currentEvent.subtitle;
    self.summaryTextView.text = currentEvent.summary;
    self.avgRatingLabel.text = [NSString stringWithFormat:@"%.1f",currentEvent.avgRating];
    [self setTitle:currentEvent.title];
    [self.view setNeedsDisplay];
}

I found that when the values are set for the first time, the label and text view objects are not initialized yet and thus their new values are not set. After the initial call of setCurrentEvent all goes well, but I think I am relying on lazy loading a bit too much here?

A: 

It is fine (good) to be very lazy, but you need to be careful about initialization ordering if you do not have everything set to init on demand. What I generally do is something like this

- (UILabel) dateLabel {
  if (!dateLabel) {
    dateLabel = [[UILabel alloc] initWithFrame:FRAME_POSITION];
  }

  return dateLabel;
}

That way you know with certainty that field is initialized when you access it, since the accessor is the lazy initializer. The one catch you need to be careful about recursive dependencies, but I have used this for large complicated initialization chain.

Louis Gerbarg
The trouble with that is that I am loading the view from a nib and thus would need to calculate all the frames especially for the accessor methods, which seems not too elegant, not to mention a lot of work.
mvexel
+1  A: 

Assuming it is being awaken from a nib or loaded from one:

Until your view controller's viewDidLoad method is called, there is no guarantee any of your IBOutlets are set.

What you are seeing I suspect is that the first time the values are set your view hasn't loaded yet, and by the time the values are set for the second, they have.

You should defer processing until the view is loaded, or create the views yourself as required.

EDIT

In light of your comment, it seems you are loading from a nib. In this case I would perhaps retain the instance variable (currentEvent say), then call a method like updateUI which sets the properties correctly. I would then also put updateUI in viewDidLoad so when the labels become available they are updated against the current event.

freespace
The key here was waiting for viewDidLoad. Once you helped me realize you can't depend on outlets being set before viewDidLoad, I worked it out in a way much like you suggested. Thanks.
mvexel