UITableView is a type of a view used to display the data in the form of a table. The UI control consists of one column and the number of rows can be specified by user. It inherits from UIView, UIResponder and NSObject classes. UITableView control is present in the object library in Xcode. It consists of cell of type UITableViewCell which forms the rows. The cell consists of content view, accessory view which helps us to display data and perform certain action. Currently there are 2 different styles of tableview, Plain and Grouped table view.
In this tutorial we will see how to use UITableView in a singleView application, populate the data to the table view by specifying number of rows and sections, perform some action when a row is selected.The tableview style is Plain.
The following concepts are covered in this document.
- Save data in Collections(here we use NSMutableDictionary)
- UITableViewDatasource protocol methods for populating data.
- UITableViewDelegate protocol methods for performing an action when a cell is selected.
Lets take an example of groceries list which we have to buy from a shop. List the items in the tableview and once we buy the product we mark the product in the tableview by using a check mark, check mark is accessory which can be used in UITableView.
Single View Application in XCode
- create a single view application in Xcode, name the project as “UITableViewDemo”.
- In Main.storyboard, a view is present in the viewcontroller, drag and drop a UITableView from the object library.
Declare the properties
- Connect the table view present in interface to the property.
- Declare the remaining properties required.
@interface ViewController : UIViewController @property (weak, nonatomic) IBOutlet UITableView *itemsTableView; @property (strong,nonatomic) NSMutableDictionary *itemDetailsList; @property (strong,nonatomic) NSArray *allKeys; @end
Save data in NSMutableDictionary
- We need to have some data to display in the tableview. In this example we store data in NSMutableDictionary. NSMutableDictionary is a dictionary with key-value pair that allows to modify the data present in the dictionary. It inherits from NSDictionary with modification operations. In the below code we store the item name as the key and “YES” or “NO” as the bool value to identify whether the item is purchased or not.
- We also assign all the keys of the dictionary to NSArray, as we have to display only keys in the tableview.
self.itemDetailsList = [[NSMutableDictionary alloc]init]; [self.itemDetailsList setObject:[NSNumber numberWithBool:NO] forKey:@"Whole-wheat bread"]; [self.itemDetailsList setObject:[NSNumber numberWithBool:NO] forKey:@"Brown rice"]; [self.itemDetailsList setObject:[NSNumber numberWithBool:NO] forKey:@"Tomato sauce"]; [self.itemDetailsList setObject:[NSNumber numberWithBool:NO] forKey:@"Red-wine vinegar"]; [self.itemDetailsList setObject:[NSNumber numberWithBool:NO] forKey:@"Mustard"]; [self.itemDetailsList setObject:[NSNumber numberWithBool:NO] forKey:@"Apples"]; [self.itemDetailsList setObject:[NSNumber numberWithBool:NO] forKey:@"Cakes"]; [self.itemDetailsList setObject:[NSNumber numberWithBool:NO] forKey:@"eggs"]; [self.itemDetailsList setObject:[NSNumber numberWithBool:NO] forKey:@"Sunscreen"]; [self.itemDetailsList setObject:[NSNumber numberWithBool:NO] forKey:@"broccoli"]; self.allKeys = [[NSArray alloc]initWithArray:[self.itemDetailsList allKeys]];
UITableViewDataSource Protocol
UitableViewDataSource is a protocol which is used to construct and modify the tableview. The protocol consists of many methods, the 3 important methods are:
- numberOfSectionsInTableView: the method is used to specify the number of sections in the tableview, in our example we have only one section. Based on the number of sections the tableview is divided vertically. The method is optional.
- tableView:numberOfRowsInSection: the method is used to specify the number of rows in each section. It is a required method in the protocol.
- tableView:cellForRowAtIndexPath: the method is used to fill the cells with data. The method is called of reach row, and we are responsible to provide the appropriate data for each cell. It is a required method.
When the tableview is reloaded or refreshed, the datasource is responsible to populate the tableview with the data. First the number of section is called to get the sections and then the no. of rows in a section and for each row, cellForRowAtIndexPath is called.
In order to use the protocol, we need to conform to the protocol UITableViewDataSource in .h file and set tableview’s datasource to current instance of the class(self), the code is given below.
In ViewController.h
@interface ViewController : UIViewController<UITableViewDataSource>
In ViewController.m(the code should be present under viewDidLoad method)
self.itemsTableView.dataSource = self;
Implementing UITableViewDataSource protocol methods
- Since we are having only one section in the tableview, integer value 1 is returned.
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ return 1; }
- The number of rows is the items present in the dictionary.The count of the dictionary is returned as the number of rows.
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return [self.itemDetailsList count]; }
- Load the cells with data.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = nil; cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if(cell == nil){ cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; } // Configure the cell... cell.textLabel.text =[self.allKeys objectAtIndex:indexPath.row]; return cell; }
- Create an instance of UITableViewCell and set it to nil. In the above method of loading the cells, we try to reuse the cells which are already created, so that the memory is not allocated for the cell again.
- In our example, when the tableview is displayed for the first time, new tableviewcell is created for the cells which are visible in the simulator initially, memory is also allocated for all the cells and the cell’s content is set.when the table view is scrolled, the same cells are reused by just changing the content of the cell thus by saving the memory.In this way we can effectively manage the memory.
- Create an identifier of the cell of type NSString, which is used to identify a type of a cell that you want to create.TableView checks for the cell, whether the cell is already created by giving cellIdentifier as the parameter, using the method “dequeueReusablecellWithIdentifier”. The method returns the cell if it is already created before, otherwise it returns nil.
- If it is nil, then, allocate memory for a cell by specifying the cell style and by giving the identifier.
- Now that we have the cell, we can set the properties of the cell.Here we are setting the text for the label which is present in the cell.
- Normally cell contains ContentView and accessory view.You can also set other properties for the cell namely textlabel for the title, detailTextLabel for the subtitle and an imageview for the thumbnail in content view.
Run the application. We can see the tableview with the list of items.
Implementing UITableViewDelegate protocol methods
- Our next requirement is to check and uncheck the items ,on selection of the cell which tells us that the item is being purchased or not. If the item is purchased then the value of the item in the dictionary is set to YES otherwise the value is set to NO. To achieve this we have to make use of the accessory view present in the cell. We have to set the accessory for the cell when the user taps or selects the cell in the tableview.
- To perform some action when we interact with the tableview, we make use of UITableViewDelegate protocol. Conform to the protocol in .h file as shown below and set the delegate to current instance(self) of ViewController class.
In ViewController.h
@interface ViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>
In ViewController.m (the code should be present under viewDidLoad method)
self.itemsTableView.delegate = self;
- There are several methods present in the UITablveiwDeleagte protocol, the method “didSelectRowAtIndexpath” is called when the user taps on the cell. We will implement the method to achieve the functionality which we require.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; if(cell.accessoryType == UITableViewCellAccessoryCheckmark){ [cell setAccessoryType:UITableViewCellAccessoryNone]; [self.itemDetailsList setObject:[NSNumber numberWithBool:NO] forKey:[self.allKeys objectAtIndex:indexPath.row]]; } else{ [cell setAccessoryType:UITableViewCellAccessoryCheckmark]; [self.itemDetailsList setObject:[NSNumber numberWithBool:YES] forKey:[self.allKeys objectAtIndex:indexPath.row]]; } }
- In the above code, on selecting the cell, identify whether the cell is having checkmark, if it contains, set its accessory type to none and update the dictionary by setting the item value to “NO”, which tells us that the item is not purchased.If the cell does not have checkmark, then set the accessory view to accesorycheckmark and the update the dictionary accordingly.
- One last change should be made in “didSelectRowAtIndexPath” to make our application work correctly. Since we reuse the cell, we should also update the accessory type of the cell along with the textLabel while loading. The complete code for “didSelectRowAtIndexPath” is given below.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = nil; cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if(cell == nil){ cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; } // Configure the cell. cell.textLabel.text =[self.allKeys objectAtIndex:indexPath.row]; //Set the accessory type for the cell BOOL selectedVal = [[self.itemDetailsList objectForKey:[self.allKeys objectAtIndex:indexPath.row]]boolValue]; if(selectedVal == YES) { cell.accessoryType = UITableViewCellAccessoryCheckmark; } else{ cell.accessoryType = UITableViewCellAccessoryNone; } return cell; }