21

Wish to know more about the practical differences between init and initWithNibName. SO answers such as this suggests that it is better to call "initWithNibName" indirectly through "init".

  1. Are there any circumstances that we need to define "init" and "initWithNibName" differently ?
  2. Is it possible that any Nib file needs to be loaded more than once during a single program execution ?
  3. Are questions 1 & 2 inter-related ?
Community
  • 1
  • 1
Stanley
  • 4,446
  • 7
  • 30
  • 48

3 Answers3

32

It is not better to call initWithNibName: indirectly through init. You just want to call initWithNibName: at some point. You can do that externally or internally. Some people think it's better to do it internally. I actually have a class called "LayoutUtil" that I keep layout-related helper methods to avoid writing tedious piece of layout-related code over and over. Here is my code to load a UIViewController:

+ (id)loadController:(Class)classType {
    NSString *className = NSStringFromClass(classType);
    UIViewController *controller = [[classType alloc] initWithNibName:className bundle:nil];
    return controller;
}

And then I can just do:

MyViewController *c = [LayoutUtil loadController:[MyViewController class]];

If you want, you could add a method called ughhhh to a class and call it in there, it doesn't matter at all. The point is that it is not a better practice to call initWithNibName in the init method though, you just want to make sure you call it at some point when initiating a UIViewController.

- (id)ughhhh
{
   self = [super initWithNibName:@"Myview" bundle:nil];
   if (self != nil)
   {
   }
   return self;
}

A nib file can definitely need to be loaded more than once. Everytime you call initWithNibName on a UIViewController the xib has to be loaded. A lot of people load UIViews that are not owned by a UIViewController like this:

[[NSBundle mainBundle] loadNibNamed:@"nameOfXIBFile" owner:self options:nil];

Everytime you call this function you will be loading the nib.

There are certain cases where a nib can be cached. An example would be a UITableView -- but the table view implements it's own cache. The operating system isn't doing any caching automatically.

init and initWithNibName: are related in that initWithNibName: automatically calls init on an object.

Michael Frederick
  • 16,664
  • 3
  • 43
  • 58
  • 1
    Just a note: to assign to self, you need to have a method starting with `init` . So `- (id)initUghhhh` – benaneesh Feb 05 '15 at 20:05
13

It's not ‘better to call "initWithNibName" indirectly through "init"’. You should use whichever one suits your needs better. Saying [[UIViewController alloc] init] is exactly like saying [[UIViewController alloc] initWithNibName:nil bundle:nil], so if those are the arguments you want to pass, you might as well use [[UIViewController alloc] init].

In answer to your questions:

  1. You can define init and initWithNibName:bundle: differently if you want to. You can define just one of them. For example, UIImagePickerController only defines init, and if you try sending it initWithNibName:bundle:, it won't work properly. Or you can define some entirely different init... method. For example, UINavigationController only defines initWithRootViewController:. Whatever init methods you do define must eventually call one of its superclass's init methods.

  2. Yes, a nib can be loaded multiple times. If you create multiple instances of the same view controller subclass, it's likely that you will load the same nib multiple times. In fact, it's possible for a single instance of a view controller to load its nib multiple times. How? If a view controller's view is not currently on screen, and the system runs low on memory, the system will ask the view controller to release its view. If the view controller later needs to put its view back on the screen, it will load the nib again.

  3. Questions 1 and 2 are not related.

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • Somehow, I can not find `init()` (no argument) on the documentation (only `init(nibName:bundle:)` and `init(coder:)`), but I have confirmed that initializing a UIViewController subclass without arguments ends up executing `init(nibName: nil, bundle: nil)`. I have seen lots of blog posts suggesting that you add a convenience initializer `init()` that does exactly that, but it seems to be unnecessary/already taken care of...? – Nicolas Miari Aug 01 '18 at 07:05
2

Answer of first question

Ideally every initWithNibName calls init internally so you do not need to define both in normal case Scenario , but you can if View is also loaded from loadView in one case and fron Nib as well in another case from different Views.

Answer of Second question

Everytime View is pushed in Stack Nib is loaded

Answer of Third question

No

Mihir Mehta
  • 13,743
  • 3
  • 64
  • 88