Thursday, May 30, 2013

To Xib or Not to Xib?

Being new to iOS environment, I watched different tutorials: the latest Stanford iOS classes uses storyboard for almost all demos, reading big nerd ranch iOS programming book, Interface Builder (xib files or in their binary form nib file) are much prefer over storyboard, looking at source code in TODO sample none of those methods are used. Everything is crafted by hand, which I will call in the rest of the blog the hand-crafted approach. Which one to choose?

First of all, all of them work, it's just a matter of finding which one works best for you. Which can you app are you making? Are you working alone? Are you an addicted to IDE or you'd rather use plain old text editor? Are you more a mouse person or a a do-it-all-with-the-keyboard guy?

I try the different ways with one simple example: I want to build an App that displays a list of item. We want to create a ViewController named MyViewController which inherits from UITableViewController. All source code could be found here.

Hand-crafted


Step1: Create Xcode project with empty template

Open Xcode and go to File -> New Project, select the  Empty Application template


Step2: Add new file MyViewController

and make it extends UITableViewController

Step2: Link MyViewController to AppDelegate 

By adding property at line 4:
@interface MyAppDelegate : UIResponder 

@property (strong, nonatomic) UIWindow *window;
@property(strong, nonatomic) MyViewController *viewController;

@end

Step3: Take care of initialisation of AppDelegate

Once the application is loaded, it's the developer's duty to instantiate MyViewController. As per commonly used Delegate pattern, once app is loaded the delegate method application:didFinishLaunchingWithOptions: is called. Within this method, you should add line 6-7
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customisation after application launch.
    self.window.backgroundColor = [UIColor whiteColor];
    self.viewController = [[MyViewController alloc] initWithStyle:UITableViewStylePlain];
    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];
    return YES;
}

Step4: Implement your model in MyViewController

For the example we feed an array of fake data in it setter method.
@implementation MyViewController
NSArray *_items;

- (NSArray *)items{
    _items = [[NSArray alloc] initWithObjects:@"Item No. 1", @"Item No. 2", @"Item No. 3", @"Item No. 4", @"Item No. 5", @"Item No. 6", nil];
    return _items;
}

Step5: Display your model in MyViewController

To display the content od a cell you need to conform to protocol UITableViewDataSource, tableView:numberOfRowsInSection:  and tableView:cellForRowAtIndexPath: are the two methods responsible for the display of a cell.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return [self.items count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell;
    
    cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }
    // Configure the cell... setting the text of our cell's label
    cell.textLabel.text = [self.items objectAtIndex:indexPath.row];
    return cell;
}
That's it you're all done, run the app!

Interface Builder

Xib, nib depending if it's the next generation or not. Actually xib file is the xml source file which describes your view. Nib being the compiled version.

Step1: Create Xcode project with Single App template

Open Xcode and go to File -> New Project, select the Single View Application template


In the next step make sure you have the option Use Storyboard unchecked.

No need to add code in AppDelegate's application:didFinishLaunchingWithOptions:, the code has been added for you. See line 5-6.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    self.viewController = [[AGViewController alloc] initWithNibName:@"MyViewController" bundle:nil];
    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];
    return YES;
}

Step2: Implement your view with xib view

1. drag and drop Table view from object library in utilities bar.



2. create an outlet, drag and drop (with control key down) up to MyViewController interface.



3. link data source to file owner: right click on TableView all the way to file's owner in document view.

Step3: Implement your model in MyViewController

Same code than Hand-crafted approach step4.

Step4: Display your model in MyViewController

Same code than Hand-crafted approach step5.

Run the app an you will have the same result. As you can see there is less code to write, but the approach involved more mouse actions. One piece of code that was generated for you but which is important to understand is in step1, the call to initWithNibName:bundle:; One interesting stuff with Interface Builder is that you can mix handcrafted and interface builder. The strength of a WYSIWIG widget based tool like Interface Builder is to build complex customized view. If you have to build a Custom Cell for you TableView, you could use Interface Builder and then load the archive and associate it with the relevant object.

Storyboard

Introduced in iOS5, Storyboard carries on the WYSIWYG approach launched by Xib. Sometime seeing as a replacement of nib, it brings UI definition in one simple file rather than several xib files, also deal with transition between screen.

Step1: Create Xcode project with Single App template

Same as for Interface builder, but this time make sure Use Story board option is checked.

Step2: Make connection from storyboard to your code

1. Go to .storyboard file, select the UIViewController graphic
2. On the utilities tab, in the identity inspector, change the class field to match MyViewController
3. create an outlet: holding the ctrl key with a drag from your view in storyboard to MyViewController.h file. Once you drop you will be prompted to enter a name, and click connect. this is the magic part of Apple WYSIWYG editor and how the link to source code. All newbies get surprised here.

Step3: Connect the datasource with outlet

Remember for hand-crafted we had to implement 2 protocols data source and delegate one. Same thin here, right click on TableViewController in the storyboard. From the outlet section, drag and drop to My Table view controller. Do it for data source and delegate.



Step4: Implement your model in MyViewController

Same code than Hand-crafted approach step4.

Step5: Display your model in MyViewController

Same code than Hand-crafted approach step5.

Run the app an you will have the same result. Here again, there is less code to write, but the approach involved more mouse actions. Besides, I thing the strength of storyboard comes when you have an application with several views and transitions using segues.

As a conclusion, we've seen the different approaches, I think to start with it's easier with the hand-crafted approach as you get to understand frequently used patterns in iOS like the Delegate pattern. But then I might be biased as I have a developer background. I like the idea Xcode storyboard/xib approach , I think it's nice to prototype or to experiment (like a preview you see it right away) but at the end of the day I find source code easier to maintain. It's all written in plain code. But you know what, storyboard/xib file are be all written in plain XML too ;) Right click and open then as source code.

Do you prefer to write XML or Objective-C?



No comments:

Post a Comment

Note: Only a member of this blog may post a comment.