Thursday 23 June 2011

IPhone SDK : Using Table Views and Implements Their DataSource,Delegate

SelectFile > New Project or Apple Key + Shft + N to bring up the new project menu. Select the Applications item of the IPhone OS section from the menu on the left, and select View Based Application from the icons on the right. When prompted enter a project name, I have used TableView in the sample code.


There are four files in the Classes package;
TableViewTutorialAppDelegate.h
TableViewTutorialAppDelegate.m
TableViewTutorialViewController.h
TableViewTutorialViewController.m


Step 2: Create the Data Controller Class



In addition to the four files generated automatically we need to create a new class (and hence assosiated header and source files) to store the data to be displayed in the view. Select File > New File or press the the Command Key + N to open the New File Dialog. Create a new source file of type NSObject Subclass (I used the name DataController.m) and make sure you select the checkbox labeled Also create "DataController.h" file (This will be different based on the name you gave your source file).






In the DataController.h file add an instance of NSMutableArray to store actual data and also add helper methods to return size of array, item at a particular index and to add and delete items. Also add a property corresponding to the list to allow access. The complete file should look something like this:

1 #import
2 @interface DataController : NSObject
3 {
4 NSMutableArray *list;
5 }
6 - (unsigned)countOfList; //returns number of elements in list
7 - (id)objectInListAtIndex:(unsigned)theIndex; //returns object at given index
8 - (void)addData:(NSString*)data; //adds data to the list
9 - (void)removeDataAtIndex:(unsigned)theIndex;
10 @property (nonatomic, copy, readwrite) NSMutableArray *list;
11 @end

Step 2 b: Implement methods of Data Controller
First synthesize the getters and setters for the list proporty by adding @synthesize to after line 11 in DataController.m. Now implement the methods defined in the header file.

Method: countOfList
The simplest method is the list count, just call the count method on the list property and return the result.
1 - (unsigned)countOfList
2 {
3 return [list count];
4 }


Method: objectInListAtIndex
Next and just as simple is to return the element at a specific index of the list just call the objectInListAtIndex method of the list and return the result.

1 - (id)objectInListAtIndex:(unsigned)theIndex
2 {
3 return [list objectAtIndex:theIndex];
4 }


Method: removeDataAtIndex
Just add the call to the list structure.

1 - (void)removeDataAtIndex:(unsigned)theIndex
2 {
3 [list removeObjectAtIndex:theIndex];
4 }


Method: addData
I am currently using an NSString to store data but you probably want to create a domain object in a real program.

1 - (void)addData:(NSString*)data;
2 {
3 [list addObject:data];
4 }

Method: setList
We also override the set list method to make sure the mutable array remains mutable.

1 // Custom set accessor to ensure the new list is mutable
2 - (void)setList:(NSMutableArray *)newList
3 {
4 if (list != newList)
5 {
6 [list release];
7 list = [newList mutableCopy];
8 }
9 }



Method: Init and dealloc
Used to initilize the objects and free mermory respectively.

1 - (id)init
2 {
3 if (self = [super init])
4 {
5 //Instantiate list
6 NSMutableArray *localList = [[NSMutableArray alloc] init];
7 self.list = localList;
8 [localList release];
9
10 //Add initial Data
11 [self addData:@"Item 1"];
12 [self addData:@"Item 2"];
13 }
14 return self;
15 }


1 - (void)dealloc
2 {
3 [list release];
4 [super dealloc];
5 }



Step 3: Update Table View Controller

Currently the TableViewTutorialViewController inherits from the UIViewController class we need to change this to the UITableViewController. Moreover we need to add a data controller class to supply data to be displayed in the rows of the table view. For this we will add the @class declarative to our view controller header file and also create an instance of this data view class and add a property for that instance. In addition we also create a view to store the tableview and create a corresponding property. The code for TableViewTutorialViewController.h should look something like this:

1 #import

2 @class DataController;
3 @interface TableViewTutorialViewController : UITableViewController
4 {
5 DataController *dataController;
6 UIView * myView;
7 }
8
9 @property (nonatomic, retain) DataController *dataController;
10 @property (nonatomic, retain) UIView * myView;
11 @end


Step 4: Implement Table View Controller Class
The code for the of TableViewTutorialViewController.m file is shown below I will individually explain the purpose of individual lines or groups of lines . Broadly what we are doing is drawing the interface (See initWithStyle and loadView), connecting it to this controller object (See loadView line 24 and 25) and then implementing the callbacks and event handlers. (See all other mehods)

//Line 1 should already exist in the auto generated file but add line to because we are going to be using methods
//from the data controller class.
1 #import "TableViewTutorialViewController.h"
2 #import "DataController.h"

//Line 3 is auto generated but we add lines 4 nd 5 to create getters and setters for the corresponding attributes
3 @implementation TableViewTutorialViewController
4 @synthesize dataController;
5 @synthesize myView;


Method: initWithStyle
//Constructor Equivelent: used to initilize view controller (self) and data controler
6 - (id)initWithStyle:(UITableViewStyle)style
7 {
8 if (self = [super initWithStyle:style])
9 {
10 self.dataController = [[DataController alloc] init];
11 }
12
13 return self;
14 }


Method: loadView

//Define the interface and connect to controller object by specifying self as delegate and data source

15 -(void)loadView
16 {
17 // create and configure the view
18 CGRect cgRct = CGRectMake(0, 10, 320, 400); //define size and position of view
19 myView = [[UIView alloc] initWithFrame:cgRct]; //initilize the view
20 myView.autoresizesSubviews = YES; //allow it to tweak size of elements in view
21 self.view = myView; //set view property of controller to the newly created view
22 UITableView * tableView = [[UITableView alloc] initWithFrame:cgRct style:UITableViewStylePlain];
23 tableView.editing = YES; //This allows user of progrm to add or remove elements from list
24 tableView.dataSource = self;
25 tableView.delegate = self; //make the current object the event handler for view
26
27 [self.view addSubview:tableView];
28 }


Method: numberOfSectionsInTableView

//We have to implement this as the object is the data source for the table view
//Hard coded number of sections in table to 1 as we are only making a single list for this example
29 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
30 {
31 return 1;
32 }


Method: numberOfRowsInSection
//We have only one section and that section has a single datasource so we just return the number of elements in
//the datasource. We have the plus one because we want to add a speacial item at the top of the list which allows //us to add more items to the list. We see how that is done later

33 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
34 {
35 // Only one section so return the number of items in the list
36 return [dataController countOfList]+1;
37 }


Method: cellForRowAtIndexPath

//This is a call back invoked by the interface when drawing the table view. This method will create a cell for each
// row and add text to each cell dependeing on the string retrieved from the datasource. Note this is called for each
/index from zero to the number or rows returned by the previous method (numberOfRowsInSection). The zeroth
//row is hard coded to display the text "New Item" this is used to add new rows to the table.

38 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
39 {
//Try to get rusable cell
40 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CellIdentifier"];
41 if (cell == nil)
42 {
//If not possible create a new cell
43 cell = [[[UITableViewCell alloc] initWithFrame:CGRectMake(0,0,0,0) reuseIdentifier:@"CellIdentifier"]
autorelease];
44 cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
45 }

46 // Get the string to display and set the value in the cell
47 if(indexPath.row == 0)
48 {
//The first (or zeroth cell) contains a New Item string and is used to add elements to list
49 cell.text = @"New Item...";
50 }
51 else
52 {
//Retreive text from datasource, the -1 accounts for the first element being hardcoded to say new Item
53 cell.text = [dataController objectInListAtIndex:indexPath.row-1];
54 }
55 return cell;
56 }



Method: editingStyleForRowAtIndexPath

//This defines for each row its editing style, i.e. whether it shows a remove sign (Red circle with subtract sign) or
//and add sign (Green circle with addition sign). I have hard coded the first row (the one that says "New Item") to display the add sign and all others to display the subtract sign.

57 - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:
(NSIndexPath *)indexPath
58 {
59 if(indexPath.row == 0)
60 {
61 return UITableViewCellEditingStyleInsert;
62 }
63 else
64 {
65 return UITableViewCellEditingStyleDelete;
66 }
67 }



Method: commitEditingStyle
//This method is invoked when the user has finished editing one of the rows of the table. The three parameters
//respectivly proivide, the table being edited, the style of the row being edited (Add or Delete) and the row being
//edited. If the style is delete we remove the corresponding item from the data source and then delete the row from
///the view. If the style was add we add another element to the data source and relode the data into the table view.
//In reality add item will probably load a new view which allows the user to enter text but that is left to another
//tutorial for now we are hard coding the text to be added.

68 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath
69 {
70 // If row is deleted, remove it from the list.
71 if (editingStyle == UITableViewCellEditingStyleDelete)
72 {
73 [dataController removeDataAtIndex:indexPath.row-1];
74 [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
75 }
76 else if(editingStyle == UITableViewCellEditingStyleInsert)
77 {
78 [dataController addData:@"New Row Added"];
79 [tableView reloadData];
80 }
81 }


82 - (void)dealloc
83 {
84 [super dealloc];
85 }

86 @end

Step 5: Loading the TableView
In the TableViewTutorialAppDelegate.m file's applicationDidFinishLaunching method initialize the tableview controller and add it as a sub view. The code should look something like this.

1 - (void)applicationDidFinishLaunching:(UIApplication *)application
2 {
3 viewController = [[TableViewTutorialViewController alloc] initWithStyle:UITableViewStylePlain];
5 [window addSubview:viewController.view];
6 [window makeKeyAndVisible];
7 }

Step 6: Try it out

No comments:

Post a Comment