Adding cells programmatically to UITableView

By | January 4, 2018
Questions:

I’ve just recently started programming for the iPhone and I’m making an application that connects to a database and gets a set of row names and displays them. When selected, the rows background colour change ie you can make multiple selections and they will all be different colours. So I’m getting the XML back from the server no problem and I have created a UITableView to display the cells in. However, I have no idea how to add the cells into the table. I had a look at insertRowsAtIndexPaths but I’m not sure how to use it? As I understand, insertRowsAtIndexPaths takes two parameters:

An NSArray that contains what row the cell is supposed to be in and in what section. The problem with this is that my app will have a dynamic number of rows. How would I go about creating the NSArray if I don’t know how many rows I will have? Can I use NSMutableArray?

The second parameter it takes is an animation – that’s pretty straightforward.

Another issue I am having is where do I actually create the cells? How do you pass the cells to the tableview?

I’ve tried reading the documentation but it just doesn’t seem very clear! Here is the code I have at the moment inside the loadview method of the view controller:

 //Before this I get the XML from the server so I am ready to populate
 //cells and add them to the table view
 NSArray *cells = [NSArray arrayWithObjects:
                   [NSIndexPath indexPathForRow:0 inSection:0],
                   [NSIndexPath indexPathForRow:1 inSection:0],
                   [NSIndexPath indexPathForRow:2 inSection:0],
                   [NSIndexPath indexPathForRow:3 inSection:0],
                   [NSIndexPath indexPathForRow:4 inSection:0],
                   [NSIndexPath indexPathForRow:5 inSection:0],
                   [NSIndexPath indexPathForRow:6 inSection:0],
                   [NSIndexPath indexPathForRow:7 inSection:0],
                   [NSIndexPath indexPathForRow:8 inSection:0],
                   [NSIndexPath indexPathForRow:9 inSection:0],
                   [NSIndexPath indexPathForRow:10 inSection:0],
                   [NSIndexPath indexPathForRow:11 inSection:0],
                   [NSIndexPath indexPathForRow:12 inSection:0],
                   nil];
[eventTypesTable beginUpdates];
[eventTypesTable insertRowsAtIndexPaths:cells withRowAnimation:UITableViewRowAnimationNone];
[eventTypesTable endUpdates];
Answers:

I think you’re approaching this from the wrong direction. UITableViews don’t work as you are expecting. insertRowsAtIndexPaths is for inserting new rows into a table, rather than for populating it in the first instance.

UITableViews work by calling a number of delegate methods that allow you to present your data to the table view as you need to. The framework then takes care of the heavy lifting to populate cells, handle scrolling and touch events, etc.

I would recommend that you start by reading a tutorial such as this one: http://www.iosdevnotes.com/2011/10/uitableview-tutorial/ , which looks fairly thorough to me. It explains how to set your datasource for the table and how you can configure the way your data is presented by the UITableView.

Good luck!

Questions:
Answers:

Don’t need to use insertRowsAtIndexPaths.

Check: UITableViewDataSource Protocol Reference and UITableView Class Reference

The magic happens between this three methods (UITableViewDataSource protocol methods):

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

You just need to fill an array. Yes it can be a NSMutableArray.

You can fill the array in - (void)viewDidLoad, for example:

yourItemsArray = [[NSMutableArray alloc] initWithObjects:@"item 01", @"item 02", @"item 03", nil];

And them use the data source methods like this:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    // Return the number of sections.
    // If You have only one(1) section, return 1, otherwise you must handle sections
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // Return the number of rows in the section.
    return [yourItemsArray count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }

    // Configure the cell...
    cell.textLabel.text = [NSString stringWithFormat:[yourItemsArray objectAtIndex:indexPath.row]];

    return cell;
}

Like this cells will be created automatically.

If You chage the Array, just need to call:

[self.tableView reloadData];

Questions:
Answers:
//######## Adding new section programmatically to UITableView    ############

  @interface MyViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>
    {
        IBOutlet UITableView *tblView;
        int noOfSection;
    }
    -(IBAction)switchStateChanged:(id)sender;
    @end



    @implementation MyViewController
    - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{
        self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
        if (self) {
            // Custom initialization
        }
        return self;
    }
    - (void)viewDidLoad{
        [super viewDidLoad];

        noOfSection = 2;
    }
    - (void)viewDidUnload{
        [super viewDidUnload];
    }
    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
        if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {

            return YES;
        }

        return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
    }
    #pragma mark - TableView Delegate Methods
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
        return noOfSection;
    }
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

        return 1;
    }
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
        if(indexPath.section == 2){
            return 200;
        }
        return  50;
    }

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

        static NSString *CellIdentifier = @"Cell";

        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];

            UISwitch *switchBtn = [[UISwitch alloc] initWithFrame:CGRectMake(0, 0, 20, 10)];
            cell.accessoryView = switchBtn; 

            [switchBtn addTarget:self action:@selector(switchStateChanged:) forControlEvents:UIControlEventValueChanged];
            cell.textLabel.font = [UIFont systemFontOfSize:14];
            cell.detailTextLabel.font = [UIFont systemFontOfSize:11];
            cell.textLabel.numberOfLines = 2;
            cell.detailTextLabel.numberOfLines = 2;
        }



        if(indexPath.section == 0){
            cell.textLabel.text = @"Cell-1 Text";
            cell.detailTextLabel.text = @"Cell-1 Detail text";
        }
        else if(indexPath.section == 1){
            cell.textLabel.text = @"Cell-2 Text";
        }
        else { // new added section code is here...
            cell.textLabel.text = @"New Added section";
        }
        [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
        return cell;
    }
    -(IBAction)switchStateChanged:(id)sender{
        UISwitch *switchState = sender;

        if(switchState.isOn == YES){
            NSLog(@"ON");
            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:2];
            [self insertNewSectionWithIndexPath:indexPath];
        }
        else {
            NSLog(@"OFF");
            [self removeSectionWithIndexPath:[NSIndexPath indexPathForRow:0 inSection:2]];
        }
    }
    -(void)insertNewSectionWithIndexPath:(NSIndexPath *)indexPath{


        noOfSection = 3;
        [tblView insertSections:[NSIndexSet indexSetWithIndex:2] withRowAnimation:UITableViewRowAnimationFade];
    }
    -(void)removeSectionWithIndexPath:(NSIndexPath *)indexPath{
        noOfSection = 2;
        [tblView deleteSections:[NSIndexSet indexSetWithIndex:2] withRowAnimation:UITableViewRowAnimationFade];
    }
    @end

Questions:
Answers:

You need not to worry about it. cells will be created automatically. just look at these
UITableview Class Reference

Tableview_iPhone

You have to implement UITableView dataSource and delegate Protocol. Also look at this tutorial
UITableview Tutorial

Leave a Reply

Your email address will not be published. Required fields are marked *