36

My initial view controller is loaded, and I need an NSArray to be init'd, should I take care of this in an awakeFromNib method or an initWithCoder: method? awakeFromNib seems to work nicer, as I don't need to return anything, but it works as nib files were what used to be used right? I don't want to use a method that will break soon.

And would initWithCoder: just look like:

- (id)initWithCoder:(NSCoder *)decoder {
    if (self = [super initWithCoder:decoder]) {
        self.articles = [[NSMutableArray alloc] init];
    }

    return self;
}
jackslash
  • 8,550
  • 45
  • 56
Doug Smith
  • 29,668
  • 57
  • 204
  • 388

1 Answers1

51

The point of -awakeFromNib is so that you can do init stuff when you can be sure that all your connections to other objects in the nib have been established.

The nib-loading infrastructure sends an awakeFromNib message to each object recreated from a nib archive, but only after all the objects in the archive have been loaded and initialized. When an object receives an awakeFromNib message, it is guaranteed to have all its outlet and action connections already established.

Don't forget to call super.

It is unlikely to go away any time soon, and if it did so much code uses it that the transition period would be long. Yes its name comes from the old "nib" file format but this stack overflow question clears up the differences in the file extensions.

So in summary either method will work for you as you are setting an internal instance variable for the class. Note that inside init methods (including -initWithCoder) it may not be safe to use your setter methods in case setters rely on the class being fully initialised (source WWDC 2012 video moving to modern objective-c). An example would be setting a property that references another object in the nib file.

In UIViewController subclasses -initWithCoder is only called when loading from a storyboard. As -awakeFromNib is called whether you use storyboards or not it might make more sense to use that.

Another pattern you could consider is the lazy-getter:

- (NSMutableArray *)articles{
    if (_articles){
        return _articles;
    }
    _articles = [[NSMutableArray alloc] init];
    return _articles;
}

The benefit of this approach is that if you wanted to do further setup to the array you can easily discard the array when you don't need it anymore and the next time you access the property you have a fresh one again.

shim
  • 9,289
  • 12
  • 69
  • 108
jackslash
  • 8,550
  • 45
  • 56
  • 1
    Sounds great, but `-initWithCoder:` doesn't get called on UIViewControllers. – CodaFi Mar 19 '13 at 19:06
  • 4
    I put a breakpoint in the `initWithCoder` method of a UIViewController subclass that gets instantiated from a Storyboard, and the debugger hit the breakpoint. [The docs](http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html#//apple_ref/doc/uid/TP40007457-CH10) confirm this behavior. – Jeff Jun 19 '13 at 21:00
  • either way you also get `-awakeFromNib` when loading from a storyboard. – jackslash Jun 20 '13 at 14:10
  • The nib loading system uses the NSCoding protocol to "unfreeze" objects: -initWithCoder is called as a result; – Myron Slaw Oct 09 '13 at 01:08
  • @jackslash lazy pattern could be 1 line shorter: check object for nil, if obj == nil then initialize it, else - return existing. – slxl Jan 25 '16 at 18:30
  • @slxl Sure. I just prefer testing for positive results over negative ones and shorter if expressions over the total number of lines of code. I think the above is easier to parse when reading it back. Its all opinion though. – jackslash Jan 25 '16 at 21:36
  • @jackslash let's call it "optimistic" approach :) – slxl Jan 26 '16 at 10:26
  • so I'm thinking of where would I ever have a good usecase of `initWithCoder`? Why not just ALWAYS dump everything in `awakeFromNib`? – mfaani Jan 16 '17 at 20:00
  • 2
    @Honey From my own testing, contrary to what is specified in this post, awakeFromNib method on View Controller does *not* get called if you are using the init(nibNameOrNil: , nibBundleOrNil) initializer (i.e. not using storyboards). Of course, in this case, initWithCoder doesn't get called either, but that is a reason why you wouldn't want to rely solely on awakeFromNib. – Cognitio Jul 28 '18 at 17:57