3

So it seems like I should be setting my member variables in viewDidLoad - but I am confused as to why setting these variables in initWithCoder fails, since both are called at the start of the program.

In particular I have a line of code:

[worldView setMapType:MKMapTypeSatellite];

In which worldView is a IBOutlet MKMapView object. It works under viewDidLoad, but not initWithCoder.

Joel Fischer
  • 6,521
  • 5
  • 35
  • 46
user3084415
  • 75
  • 2
  • 8

2 Answers2

5

The outlets are not yet connected when initWithCoder is called. From the documentation:

During the instantiation process, each object in the archive is unarchived and then initialized with the method befitting its type. Objects that conform to the NSCoding protocol (including all subclasses of UIView and UIViewController) are initialized using their initWithCoder: method.
...
After all objects have been instantiated and initialized, the nib-loading code reestablishes the outlet and action connections for all of those objects. It then calls the awakeFromNib method of the objects.

So awakeFromNib would be a suitable place for the custom setup of your UI elements.

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Also, asa a completion, if your variables are using the views frame, you should init them in `viewWillAppear` `viewDidAppear`. – danypata Dec 09 '13 at 21:14
  • It seems like my worldView object also does not exist in awakeFromNib. Is this expected? – user3084415 Dec 09 '13 at 22:07
  • @user3084415: No, I would all outlets to exist in awakeFromNib. – Martin R Dec 09 '13 at 22:08
  • @MartinR Putting NSLog(@"World View: %@", worldView); under awakeFromNib reveals that worldView is a nil value for some reason... I don't know why. – user3084415 Dec 09 '13 at 22:28
  • @user3084415: What exactly do you load from the nib file? A view or a view controller? – Martin R Dec 09 '13 at 22:34
  • @MartinR View controller I believe. – user3084415 Dec 09 '13 at 22:59
  • @user3084415: A view controller's *view* is loaded lazily, when it is accessed the first time. Then viewDidLoad is called. – Martin R Dec 09 '13 at 23:04
  • Sorry - what difference would this make with awakeFromNib? – user3084415 Dec 10 '13 at 00:07
  • @user3084415: It seems that my answer does not really fit your problem. If you have a custom *view* class and the view is loaded from a nib file, then you can use awakeFromNib in the view class to setup UI elements. But you have a *view controller* loaded from a nib, and the view controller's view is loaded lazily, so viewDidLoad in the view controller class is the right place. Compare http://stackoverflow.com/questions/14078708/when-to-use-viewdidload-and-when-to-use-awakefromnib. - So you might consider to accept Joel's answer instead, as he gave the correct answer first. – Martin R Dec 10 '13 at 06:35
3

The objects do not yet exist when initWithCoder is called, and they do when viewDidLoad is called. Check your initWithCoder method by logging out the value of worldView using something like:

NSLog(@"World View: %@", worldView);

and it will be nil. They will be initialized before the call to viewDidLoad, so you can set a property of that IBOutlet there.

Joel Fischer
  • 6,521
  • 5
  • 35
  • 46
  • How come there are no errors when I put my code under initWithCoder (when worldView doesn't exist yet)? If worldView does not exist, shouldn't the compiler complain since I'm trying to set variables of a nil object? – user3084415 Dec 09 '13 at 21:43
  • 3
    @user3084415: Sending messages to nil is allowed in Objective-C (and is effectively ignored for methods that do not have a return value). – Martin R Dec 09 '13 at 21:52