tentmaking
tentmaking

Reputation: 2146

awakeFromNib Not Called in iOS 9

I am running into an interesting issue. I have a view controller:

LoginViewController *viewController = [LoginViewController alloc] init];

In the methods initWithNibName:bundle: and awakeFromNib I have some initialization code. The LoginViewController has a .xib file named LoginViewController.xib.

However, building against iOS 9, those methods never get called and the code is never run. Unless however, I initialize my LoginViewController like this:

LoginViewController *viewController = [LoginViewController alloc] initWithNibName:nil bundle:nil];

Then the code is run and it works perfectly fine. It appears that the .xib file is being loaded, but initWithNibName:bundle: and awakeFromNib are never called.

Does anyone know why in iOS 9 awakeFromNib isn't getting called by default when a corresponding .xib exists? This issue did not exist in iOS 8 (awakeFromNib was called even if I just used init to initialize my view controller).

Upvotes: 0

Views: 3246

Answers (2)

Samuel Catalano
Samuel Catalano

Reputation: 13

I had the same problem. For some reason my method awakeFromNib -awakeFromNibis not called. I know that was not a good practice but if you take care about your code, you can use the NSNotificationCenter to solve this problem.

Upvotes: 0

quellish
quellish

Reputation: 21254

Changes to view controller nib loading behavior are described in the iOS 9 Release Notes:

If initialized with a nil nibName value, UIViewController.nibName has always looked for a nib with a similar name as the view controller’s class, and defaulted to that value if loadView is not overridden. Prior to iOS 9, subclasses of UIViewController that were written in Swift would require that their corresponding nib file name include the module prefix.

To improve flexibility in the event of refactoring, you can omit the module name from the nib filename in code that runs in iOS 9. UIViewController.nibName still prefers a name that contains the module prefix, but falls back to an unqualified name if a nib with the fully-qualified name is not found.

Additionally, the class documentation for UIViewController states:

If you specify nil for the nibName parameter and you do not override the loadView method, the view controller searches for a nib file as described in the nibName property.

If you are performing initialization in -initWithNibNamed:bundle: it is preferable to instead do so in -initWithCoder: and/or -loadView (depending on what you are doing). -awakeFromNib is still appropriate for the things that normally should go there.

From your question it seems that: - -initWithNibNamed:bundle: and awakeFromNib are not being invoked when the view controller subclass is instantiated with -init. - -initWithNibNamed:bundle: and awakeFromNib are being invoked when the view controller subclass is instantiated with -initWithNibNamed:bundle:.

This is a little curious. -initWithNibNamed:bundle: is the designated initializer and thus -init should be calling into it with nil arguments to trigger the behavior described above. A quick disassembly of UIKit on iOS 9 with Hopper shows that is still the case.

If you override -loadView -initWithNibName:bundle: will not attempt to load the nib for you - by overriding -loadView you are opting into doing that yourself. If you are overriding -loadView (even if you call super), remove that and the nib should load. -awakeFromNib won't be called because the view controller is the nib's owner - only the children will get that method call. If it were part of a storyboard it would be called. -awakeAfterUsingCoder:, however, will be called and may be a better place to do the work that you are attempting in -awakeFromNib.

I reduced your question to a simple test case and confirmed this behavior on with the iOS 9 and iOS 8.4 SDKs.

Upvotes: 2

Related Questions