Programmatically vs IB


#1

As an experiment, I’m trying to alter the Chapter 7 Hypnotime example so that instead of configuring the viewControllers programmatically in script (page 108 in the book) I’d configure them using only IB (because a combination approach seems doomed to failure since we have to load up an array of viewcontrollers to the tab view in code if we do it programmatically)

Anyhoo

I’ve done the following (the starting point was a new window based application, into which I copied the following

HypnosisViewController.h
HypnosisViewController.m
HypnosisView.h
HypnosisView.m
CurrentTimeViewController.h
CurrentTimeViewController.m
CurrentTimeViewController.xib

From there, I edited
HypnoTimeAppDelegate.h as follows to ass in a rootController instance variable of type UITabBarController

#import <UIKit/UIKit.h>

@interface HypnoTimeAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
    UITabBarController *rootController;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UITabBarController *rootController;

@end

HypnoTimeAppDelegate.m:

#import "HypnoTimeAppDelegate.h"

@implementation HypnoTimeAppDelegate

@synthesize window;
@synthesize rootController;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    
    // Override point for customization after application launch.
    [self.window addSubview:self.rootController.view];
	
    [self.window makeKeyAndVisible];
    
    return YES;
}

- (void)dealloc {
    [window release];
    [rootController release];
    [super dealloc];
}

Then I edited the MainWindow.xib and added a TabBarController, and set up the appropriate connections

  • App Delegate to the Tab Controller as rootController (grab.by/9OvX)
  • Set up tab item 1 to be a HypnosisViewController (grab.by/9OvO)
  • Set up tab item 2 to be a CurrentTimeViewController with a Xib name of CurrentTimeViewController (grab.by/9OvL)

So. the PROBLEM is that when I run this thing, I see the Hypnosis Tab just fine (the concentric circles) but the CurrentTimeViewController (and Xib) arent showing up.
Working: grab.by/9Ow0
Not Working: grab.by/9Ow1

Any idea where I’m going wrong?


#2

Another related question I have is… why would I create the rootController and its viewController arrays, in script? It seems simpler to me to use the MainWindow.xib and add a UITabBarController and wire it up? I guess that could be because I’m new at this and the visual version seems clearer to me.


#3

I’m not sure why in this specific case, although, if you set the rootViewController of a window in a XIB file, you shouldn’t be adding its view to the window in code. Setting the rootViewController of a window automatically installs the view controller’s view as a subview of the window.

Now, for the reason I don’t really know: instantiating view controllers in a XIB file is bad practice. Yes, you can do it, and yes, Apple does it in their template code. But, and you can quote me on this: they are wrong for doing this.

Couple of questions you may have:
Q: "Uh, Joe, you create view controllers in XIB files all of the time… in fact, the HypnosisViewController in this very exercise is an example!"
A: The HypnosisViewController is not created in HypnosisViewController.xib. A view, a button and a label, are created in this XIB file. When this XIB file is loaded in, the HypnosisViewController object has already been instantiated. It is simply loading its view from the XIB file.

Q: "Ok, then why is it okay to create views in a XIB file, but not controller objects?"
A: Two reasons. First, it is confusing. A XIB file should just be an interface, and interfaces are made up of view objects. When you start putting other types of objects in there, it forces a developer to check a XIB file to see what is really going on in an application. This takes extra time, and it is much easier to hide the behind the scenes stuff in a XIB than it is in code. And when you hide things, they become much more difficult to debug. Thus, being explicit about creating controller (and model objects) by doing so in code can save you a lot of headaches when debugging.

The other reason is that some interesting problems can arise by creating controller objects in a XIB file. Imagine if UIViewController A’s XIB file creates an instance of UIViewController B. When a low memory warning occurs, A will release B and effectively destroy B. So, you are destroying a view controller, and not just a view. Since a view controller may (and most likely will) hold state and pointers to model objects, you have to rebuild that entire hierarchy.

This can get ugly, and will only get uglier of B has XIB file that creates C, and C has a XIB file that creates D and so on. A low memory warning can then wipe out nearly every object in your application when it both did not need to and shouldn’t have.

Don’t create view controllers in a XIB file. Only create views. You will suffer much less pain.


#4

Joe

That makes sense… it’s much clearer now. I agree that instantiating the ViewControllers in code is going to lead to much more maintainable code!

:ugeek:

John