Monday, December 29, 2008

A UITableView Primer

Many people struggle with the UITableView so we'll start off with the basics here.  I'll cover the basics in this tutorial and in future tutorials try and build on that.

How I think of the UITableView is that I have an array, and it uses that arrays attributes to display my information in a very nice way.  So the first thing that should be done should be to create a "Navigation Based Application" in XCode, I'll call mine "TableViewPractice."  We see two classes: the delegate, and the RootViewController.  In short, what is happening is that the delegate is making sure that the view is created and shown by the RootViewController.

First let's add a couple things in the app delegate's header file.  We'll add a property for an NSArray -- So everything after your imports and opening comments becomes this:


@interface TableViewPracticeAppDelegate : NSObject {

    UIWindow *window;

    UINavigationController *navigationController;

  NSArray *theArray;

}


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

@property (nonatomic, retain) IBOutlet UINavigationController *navigationController;

@property (nonatomic, retain) NSArray *theArray;


-(void) createArray;


@end

Now we have the .h file ready, so let's jump into the .m file.  First off, we need to synthesize the array, so do that by adding this after the @implementation line:

@synthesize theArray;


I typically create another class in the delegate to create the array of information which needs to be displayed using my UITableView.  I've called mine createArray  as you can see above, and it can be void for my particular implementation.  We'll keep it simple, something like this:

- (void)createArray {

    NSArray *myArray = [[NSArray alloc] initWithObjects:@"Hello", @"World", nil];

    theArray = myArray;

}


The delegate looks good, let's move onto the UITableView class (RootViewController)


Now, each method in this will be called automatically, so no need to link anything up per se, because a UITableView class is ready to run with these methods.  I'll try and explain each one briefly before showing how we will implement it, they are fairly self explanatory but make sure you understand them and use them properly.


- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView

Return the number of sections in a tableview, since our array is very basic, we can simply return 1.


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

This can be used to specify how many rows are in each section, since our UITableView only has one section, we can use this fairly easily as well.


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

This still remains fairly simple in a basic implementation, but can be used to change the appearance of the given row in the UITableView.  This also exposes us for the first time to "indexPath."  Don't be intimidated by this, this can be used greatly to our advantage.


- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

This can be used to handle if a row is touched.  You can choose to implement this or not.  In this basic example we will only use this is a very simple form.


There are a few more methods that go into editing a UITableView, but since we aren't going to be implementing that we'll cover it at the time in which it seems more relevant.


Let's get down to the actual implementation inside the UITableView!


Like I mentioned earlier, this is basically all structured around the array and its traits.  Knowing that the implementation should be fairly simple.  To do this I will use the app delegate to give us the array.  We can do that by using this line of code:

TableViewPracticeAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];


This is a powerful line of code, and will make it so the number of rows can easily be expressed:

return [[appDelegate theArray] count];


So that whole section will become:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    TableViewPracticeAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];

     return [[appDelegate theArray] count];

}


Pretty simple, right?  With only one section this becomes easy, because we know we can return the count and it will work.  For multiple sectioned tables, we would want to create a switch, but this is clearly not needed in our implementation.


For the cellForRowAtIndexPath method we can use the app delegate again.  Under the comment that already exists that reads "// Setup the cell" we can put:

TableViewPracticeAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];

cell.text = [[appDelegate theArray] objectAtIndex:indexPath.row];

   

That whole section (For copy and paste purposes) should now read:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    

    static NSString *CellIdentifier = @"Cell";

    

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) {

        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];

    }

    

    // Set up the cell...

TableViewPracticeAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];

cell.text = [[appDelegate theArray] objectAtIndex:indexPath.row];

   

return cell;

}


Now this should look how we want it, try and run it!  


I mentioned earlier that we would only go into the basics of the didSelectRowAtIndexPath.  So if we peak at that we can change it to:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath {

    // Navigation logic may go here. Create and push another view controller.

    // AnotherViewController *anotherViewController = [[AnotherViewController alloc] initWithNibName:@"AnotherView" bundle:nil];

   // [self.navigationController pushViewController:anotherViewController];

   // [anotherViewController release];

   [tableView deselectRowAtIndexPath:indexPath animated:YES];

}


I left Apple's little comments in there because it will make sense when we try to implement it later.  All this will do will deselect the row that was selected, so you will see it selected for a second, then deselect itself with some nice fading animation.  Since this is only one level deep this is basically all it will need.


To sum up what is happening in a basic way:

-The UITableView is calling all of those methods automatically

-We're using the indexPath to find out where we are at that particular moment

-We're setting the text of each row using indexPath.row.


In the next posts I'll be sure to cover editing, more on selecting, and other stuff we can do with UITableViews.


Here's the source of this tutorial: Download Tutorial Source Code

1 comment:

  1. Did you forget the:

    //make the array
    [self createArray];

    In the 'applicationDidFinishLaunching' section? I didn't see it. I added it and then the app worked.

    ReplyDelete