Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIViewController: [super init] calls [self initWithNibName bundle:]

I have two init functions in my UIViewController subclass:

- (id)init
{
    self = [super init];
    if (self)
    { 
           // Custom stuff
        return self;
    }
    return nil;
}

and

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName: nibNameOrNil 
                           bundle: nibBundleOrNil];
    if (self) 
    {
        // Custom stuff
    }
    return self;
}

I put the init function in to avoid the call to the initWithNibName:bundle: method. I am trying to experiment with taking the xib file out. Unfortunately, calling this init [[Myclass alloc] init] calls initWithNibName:bundle: through the call to [super init].

First, where in the documentation should I be reading so that I would have expected the call to the parent init method to call my own initWithNibName:bundle: method?

Second, how is this a good design choice on Apple's part. I am not seeing why this is desirable behavior? (It may be that I am just not getting the big picture here so please feel free to clue me in.)

Third, how do I get around it best. Do I just take the initWithNibName:bundle: out of my code? Is there never a case where I would like the option of using either a xib or a manual instantiation of the class.

like image 518
StoneBreaker Avatar asked Dec 04 '12 14:12

StoneBreaker


2 Answers

Usually I have to initialise my view controllers with managed object context. I implement simple -(id)initWithContext: method in which I call super's initWithNibName:bundle: method. This way I can define my own xib name.

Not sure about the first part of you question (the reading thing, that is), but Apple's class templates for VC's show that they have their own initWithNibName:bundle method which calls on super with same parameters as they are given. Hence from your situation I'd say that exactly this is designated initialiser and it's not "safe" to call simple init method on super as it will invoke initWithNibName:bundle. I believe UIViewController's init looks like this:

- (id)init
{
  self = [self initWithNibName:nibNameDerivedFromClass bundle:probablyNilOrMainBundle];

  if (!self) return nil;

  // some extra initialization

  return self;
}

Since the super class doesn't have initWithNibName:bundle it has to call method on itself making it the designated initialiser. Since you have overridden it, ObjC's runtime replaces self in that method with your class.

like image 179
Eimantas Avatar answered Nov 04 '22 16:11

Eimantas


If you want to exclude Interface Builder from the creation of your UIViewController's GUI, you have to override loadView and create the view yourself. Don't implement initWithNibName:bundle:.

- (void)loadView {
    // Init a view. The frame will be automatically set by the view controller.
    UIView *view = [[UIView alloc] initWithFrame:CGRectZero];

    // Add additional views (buttons, sliders etc.) to your view here.

    // Set the view controller's view to the new view.
    self.view = view.
}
like image 2
DrummerB Avatar answered Nov 04 '22 17:11

DrummerB