google
yahoo
bing

Upcoming Classes

RSS Feeds

Categories

Archive

Site search

Xcode Templates

Aaron Hillegass’ last post on initializers for UIViewController was spot-on. In fact, when you come to our iPhone Bootcamp, you’ll learn all about it.

However, the extra typing every time we create a file is a nuisance. When you create a subclass of a UIViewController, chances are you really want to get to work on the important stuff. In this post, I’ll show you how to set up your Xcode template for UIViewController subclasses with a XIB file so that you don’t have waste any time creating your next iPhone app.

Currently, Xcode templates are located at:

/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/

(I say currently because there is no guarantee the next major version of Xcode will look for templates there. You are safe for now, though.)

What we want to do is change the template for creating UIViewController subclasses. That template is located here:

/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/File Templates/Cocoa Touch Class/UIViewController subclass

Quick Finder Tip: When the Finder is active, hit Cmd-Shift-G. Copy and paste the previous path in to the sheet that appears and hit Go. If you installed the Developer tools to another directory, you’ll have to replace /Developer/ with that path. Optionally, you can spotlight for FILEBASENAMEASIDENTIFIER and it will point you within the vicinity. (FILEBASENAMEASIDENTIFIER is the keyword in Xcode templates that gets replaced by the name of the file you are prompted to enter.)

In this directory, there is a property list and two directories. (For the more curious, you can open up the property list for some interesting Xcode hacking.) The directory we are interested in is UIViewController subclass with XIB.pbfiletemplate. Open that directory.

From that directory, open class.m in Xcode. Mine looks like the following:

//
//  «FILENAME»
//  «PROJECTNAME»
//
//  Created by «FULLUSERNAME» on «DATE».
//  Copyright «YEAR» «ORGANIZATIONNAME». All rights reserved.
//

«OPTIONALHEADERIMPORTLINE»

@implementation «FILEBASENAMEASIDENTIFIER»

- (id)init
{
    self = [super initWithNibName:@"«FILEBASENAMEASIDENTIFIER»"
                           bundle:nil];
    // Initialize ivars not related to [self view] or XIB objects

    return self;
}
- (id)initWithNibName:(NSString *)nibNameOrNil
               bundle:(NSBundle *)nibBundleOrNil
{
    return [self init];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Init ivars that need anything from the XIB or [self view]
}

- (void)viewDidUnload
{

}

- (void)dealloc
{
    [super dealloc];
}

@end

You can copy and paste this text in to that file and save it or roll your own. Now you can imbibe Aaron’s wisdom without having to do any real work!

Comments

Comment from Jonathan Wight
Time: August 13, 2009, 9:21 pm

I used NSStringFromClass([self class]) for the NIB name. Makes it immune to class renames (as long as you remember to rename the xib file too).

Don’t actually agree with much (any?) of your last couple of posts but hey keep doing what you’re doing.

Comment from Brian Hardy
Time: August 14, 2009, 7:07 am

On SDK 3.0, at least, none of this is necessary if you want to use the class name as the Nib name. From the docs for initWithNibName:bundle:

If you specify nil for the nibName parameter and do not override the loadView method in your custom subclass, the default view controller behavior is to look for a nib file whose name (without the .nib extension) matches the name of your view controller class. If it finds one, the class name becomes the value of the nibName property, which results in the corresponding nib file being associated with this view controller.

Taking advantage of this, you can simply call init and everything works. And as an added bonus, you don’t lose the ability to use the designated initializer to specify a different nib or bundle, if you so choose.

Comment from Joe Conway
Time: August 14, 2009, 10:21 am

Part of the usefulness of this technique is preventing someone using your class from specifying the wrong nib file. The nib file for a UIViewController is an implementation detail of that VC the same way loadView is an implementation detail. It shouldn’t really be exposed to other objects.

Comment from Brian Hardy
Time: August 14, 2009, 10:35 am

If you want to prevent someone from specifying another nib file, that’s up to you. If you’re creating a view controller class that loads its view from a nib, you specify the “contract” between your class and its interface by using the IBOutlet and IBAction modifiers. As long as the interface provided to the class satisfies that contract, everything should work.

So in the event that you wanted to use multiple, different Nib files for, say, multiple instances of a single class, you could easily do that given the standard API. You still have the option to fall back on the default behavior and load the class-named nib with “init”

Comment from Joe Conway
Time: August 14, 2009, 10:52 am

Writing reusable code requires this kind of safety. For example, Apple employs the same technique with ABPeoplePickerNavigationController, UNavigationController, etc. Try loading those from another nib file, it won’t let you. It is rare that you would want multiple user interfaces for the same functionality, the only example I could think of is if you wanted a “skinnable” view controller. The majority of the time we create view controllers, we lock in the nib file because it is an implementation detail of the view controller. Because this is the majority, it makes sense for our view controller subclasses to “default” to this type of behavior.

That being said, the IBOutlets and IBActions of a view controller aren’t the only contract being made. There is the matter of hooking up delegates, inter-NIB connections and other top level objects that may not be connected to the File’s Owner.

Comment from Brian Hardy
Time: August 14, 2009, 12:55 pm

The framework examples you give (PeoplePicker, etc) do not use Nib files to load their views, so it makes sense that they would prevent you from trying to force that upon them. If you want to create a view controller subclass that gets its view from a nib and also lock that nib to the view controller’s implementation, the technique you outline is perfectly acceptable, but it is, in my opinion, unnecessary.

Regarding your mention of inter-NIB connections and top level objects unconnected to File’s Owner, if your view controller subclass somehow depends on those things being in place in order to work correctly, that’s a problem. There should be no reason that a delegate must be specified in a NIB file as opposed to code somewhere. The view controller should not care.

Write a comment