Reputation: 3022
Is there a good overview of initWithNibName
, awakeFromNib
, and viewDidLoad
that lays out the best way to use each of these and describes exactly what each does? I find these very confusing. In the template that's generated with a View Controller, the comment about initWithNibName
says:
The designated initializer. Override to perform setup that is required before the view is loaded.
Except that this method never seems to be called (I'm using IB to set up the View Controller). So should I use awakeFromNib
or viewDidLoad
to initialize instead?
Upvotes: 19
Views: 12993
Reputation: 1677
viewDidLoad can get called more than once so it is not an appropriate place for most initialization (although in practice it's called just once unless you are meddling) - that is why awakeFromNib is special and very necessary: it only gets called once.
viewDidLoad doesn't exist on UIView - UIView has awakeFromNib for initialization and there are no other sensible options.
For the past six months I have been happily using awakeFromNib with storyboards (a single storyboard for an app) without any trouble at all and it has behaved perfectly with all outlets configured as specified in the documentation. Then today I took some code apart and put in a new view controller and views and none of it is working as I have experienced in the past i.e. all outlets nil in awakeFromNib. My theory is simple - the SDK sucks because it's very easy to do something trivial somewhere in your chain of controllers/views and classes and break everything.
Now I'm off to research this pointless topic, yet again, when all I need is a simple consistent place to do initialization.
Upvotes: 0
Reputation: 351
I just finished doing some research on this topic so I thought I'd share a few of the things I learned.
There's nothing wrong with using awakeFromNib
with views for the iPhone. See this Apple Dev document.
initWithCoder
is not a good place to do initialization when the view is loaded from a NIB file because other items in the same NIB file may or may not have been initialized at that point. So an outlet might still be nil, for example. All items in the same NIB file are guaranteed to be initialized properly when awakeFromNib
is called.
viewDidLoad
is a good place to do setup work in the viewController.
So why would one want to use awakeFromNib
in the view? One reason I can think of is if you have stuff you want to do after the view has been initialized and hooked up to the other objects in the NIB file, but you want to encapsulate it in the view only. This reduces linkage with the view controller.
Upvotes: 35
Reputation: 78343
If you're creating your views in IB, then you should use viewDidLoad
. That will be called every time the view is initialized to be put up. You use initWithNibName
: when you're creating your view in code. You shouldn't use awakeFromNib
with views for the iPhone.
The reason that initWithNibName
is not seeming to be called is that interface builder actually creates a real instance of your view controller and then serializes that view. So, when you create the view controller in IB (add it to your project, basically), IB calls initWithNibName
, but unless you have overridden the default encodeWithCoder
:, any transient variables that you've set up there will be gone when the view is loaded from the nib (deserialized). This is generally okay since you usually want to set up your view with information specific to your applications current, running context rather than pre-determined initializers.
Even if you are programmatically creating views and view controllers, however, you can still put all the initialization in viewDidLoad
. This is often better because if your view ends up getting cached (unloaded) and then brought back onto the screen, viewDidLoad
can be called again while your initializer wouldn't necessarily be. For example, you create a view programmatically and push it onto a navigation controller's stack—later the view has been covered up and a memory warning is issued so the nav controller "unloads" your view but doesn't release the object—when the view comes back (other views get popped off), the nav controller will call viewDidLoad
again so you can re-initialize, but initWithNib
will not be called again. Note that this is a rare case and most people's applications will die horribly for other reasons at this point anyway, however.
Upvotes: 24