3
votes

A view controller FooViewController needs to do some initialization when it's created (of itself, not of the managed view - before the view is even loaded).

I want to be able to create it in two ways:

  1. Programmatically, possibly with some arguments:

    FooViewController *fooViewController = [[[FooViewController alloc] initWithSomeData:data] autorelease];
    [self.navigationController pushViewController:fooViewController animated:YES];
    
  2. In Interface Builder.

For (1) I would write the initializers like this:

- (id)initWithSomeData:(Data *)data     // designated initializer
{
    if (self = [super initWithNibName:@"FooView" bundle:nil]) {
        self.title = "Foo";
        // perform initialization
    }
    return self;
}
- (id)init
{
    return [self initWithSomeData:nilOrSomeDefaultValue];
}

// ... other initializers that call the designated initializer

(I hardcode the nib name since the controller always uses the same view configuration and because which view it uses doesn't concern the callers at all)

When created in Interface Builder, I would want the end result be the same as if the object was initialized with the parameterless init.

Now if I just do:

- (id)initWithCoder:(NSCoder *)decoder
{
    return [self init];
}

The title, wantsFullScreenLayout and nibName properties which are set in the Inspector in Interface Builder would then be ignored, but that's OK. The nibName is hardcoded in init and title is set there in case the controller is instantiated programmatically anyways.

The problem is that parentViewController isn't set (the default initWithCoder: would set it based on the hierarchy of objects in the NIB).

How can I get the parent object from the nib? I would then change initWithCoder: to something like:

- (id)initWithCoder:(NSCoder *)decoder
{
    if (self = [self init]) {
        _parentViewController = [decoder parentObject];
    }
    return self;
}

Or should I be using some different approach to create controllers which can be instantiated both programmatically and in IB?

2

2 Answers

0
votes

Don't, don't, don't try to make a viewcontroller that works with and without a nib. It will be a nightmare because nibloading uses some of the normal entry points and provides new ones, and it will be fragile with respect to OS revisions.

What you can do is it make the view controller always load from a nib, then give yourself a convenience initializer to go through the nib:

- (id) init {
  return [[[self class] alloc] initWithNibNamed:@"MyNibName" bundle:nil];
}

Then you can reference it through other nibs the normal way, and just call the convenience init method when you don't want to explicitly deal with the nib.

0
votes

Why not do init stuff in viewDidLoad - when creating outside of IB, you can set initial values with some other methods or properties after initialization, but before viewDidLoad is called.