Programmatically create tabbar hierarchy

I try and avoid using Interface Builder in my projects as much as possible as it's just not as flexible as I'd like it to be. With IB I often end up with some settings defined in IB and some defined in code which then makes the code trickier to maintain as we now have multiple sources of truth for that view. Below is my implementation of how to programmatically create and populate a tabbar and so avoid using IB.

In comes in two parts:

  1. plist defining the hierarchy
  2. Method read plist and create hierarchy

Plist Structure

<plist version="1.0">
<array>
	<dict>
		<key>TabBarTitle</key>
		<string>HOME_TAB</string>
		<key>TabBarImage</key>
		<string>tabbar_home_icon.png</string>
		<key>RootViewController</key>
		<string>HomeViewController</string>
	</dict>
</array>
</plist>

The above plist is used to define the tabs that the controller will have. As you can see it has 3 properties for each tab:

  • Title
  • Icon
  • ViewController

(The plist file is called ApplicationHierarchy)

Method without using a xib

-(void)createApplicationHierarchy{
	
	NSString *applicationHierarchyPlistFilePath = [[NSBundle mainBundle] pathForResource:@"ApplicationHierarchy" ofType:@"plist"];
	
	if (applicationHierarchyPlistFilePath != nil) {
		NSArray *applicationHierarchy = [[NSArray arrayWithContentsOfFile:applicationHierarchyPlistFilePath] retain];
		
		NSMutableArray *navigationElements = [[[NSMutableArray alloc]init] autorelease];
		
		for (int x = 0; x < [applicationHierarchy count]; x++) {
			
			NSDictionary *tabbarDictionary = [applicationHierarchy objectAtIndex:x];
			
                        //Create tabbar's element's root viewcontroller
			Class rootViewControllerClass = NSClassFromString ([tabbarDictionary objectForKey:@"RootViewController"]);
			id rootViewController = [[rootViewControllerClass alloc]init];
			UINavigationController *tabRootViewNavigationController = [[UINavigationController alloc]initWithRootViewController:rootViewController];
			[rootViewController release];
			
                        //Give tab bar element a title
			NSString *tabBarTitle = NSLocalizedString([tabbarDictionary objectForKey:@"TabBarTitle"], @"");
                        
                        //Give tab bar element an image
			UIImage *tabBarImage = [UIImage imageNamed:[tabbarDictionary objectForKey:@"TabBarImage"]];
			
                        //create tabbar item and pass it configuration defined aboce
			UITabBarItem *tabBarItem = [[UITabBarItem alloc]initWithTitle:tabBarTitle image:tabBarImage tag:x];
			tabRootViewNavigationController.tabBarItem = tabBarItem;
                        [tabBarItem release];
			[navigationElements addObject:tabRootViewNavigationController];
			[tabRootViewNavigationController release];
			
		}
		
		[applicationHierarchy release];
		
		self.tabBarController.viewControllers = [NSArray arrayWithArray:navigationElements]; //this "tabBarController" is attached to MainWindow.xib
		
	}
	
}

Method with a xib

-(void)createApplicationHierarchy
{  
    
    NSString *applicationHierarchyPlistFilePath = [[NSBundle mainBundle] pathForResource:@"ApplicationHierarchy" ofType:@"plist"];  
    
    if (applicationHierarchyPlistFilePath != nil) {  
        NSArray *applicationHierarchy = [[NSArray arrayWithContentsOfFile:applicationHierarchyPlistFilePath] retain];  
        
        NSMutableArray *navigationElements = [[[NSMutableArray alloc]init] autorelease];  
        
        for (int x = 0; x < [applicationHierarchy count]; x++) {  
            
            NSDictionary *tabbarDictionary = [applicationHierarchy objectAtIndex:x];  
            
            //Create tabbar's element's root viewcontroller  
            Class rootViewControllerClass = NSClassFromString ([tabbarDictionary objectForKey:@"RootViewController"]);  
            id rootViewController = [[rootViewControllerClass alloc]initWithNibName:[tabbarDictionary objectForKey:@"RootViewController"] bundle:nil];  
            UINavigationController *tabRootViewNavigationController = [[UINavigationController alloc]initWithRootViewController:rootViewController];  
            [rootViewController release];  
            
            //Give tab bar element a title  
            NSString *tabBarTitle = NSLocalizedString([tabbarDictionary objectForKey:@"TabBarTitle"], @"");  
            
            //Give tab bar element an image  
            UIImage *tabBarImage = [UIImage imageNamed:[tabbarDictionary objectForKey:@"TabBarImage"]];  
            
            //create tabbar item and pass it configuration defined aboce  
            UITabBarItem *tabBarItem = [[UITabBarItem alloc]initWithTitle:tabBarTitle image:tabBarImage tag:x];  
            tabRootViewNavigationController.tabBarItem = tabBarItem;  
            [tabBarItem release];  
            [navigationElements addObject:tabRootViewNavigationController];  
            [tabRootViewNavigationController release];  
            
        }  
        
        [applicationHierarchy release];  
        
        self.tabBarController.viewControllers = [NSArray arrayWithArray:navigationElements]; //this "tabBarController" is attached to MainWindow.xib  
        
    }  
    
}

The beauty of either approach is that in order to add/remove tabs in your application you just alter the elements to the plist.

What do you think? Let me know by getting in touch on Twitter - @wibosco