Skip to content

DD 4.8. Deleting Cells and Sections from Table Views

rayastar edited this page Feb 8, 2015 · 1 revision

Problem

You want to delete sections and/or cells from table views using animations.

Solution

In order to delete sections from a table view, follow these steps:

  1. First delete the section(s) in your data source, whether you are using a data model like Core Data or a dictionary/array.

  2. Invoke the deleteSections:withRowAnimation: instance method of UITable View on your table view. The first parameter that you need to pass to this method is of type NSIndexSet, and this object can be instantiated using the indexSetWi thIndex: class method of NSIndexSet class, where the given index is an unsigned integer. Using this approach, you will be able to delete only one section at a time. If you intend to delete more than one section at a time, use the indexSetWithIndex esInRange: class method of NSIndexSet to create the index set using a range, and pass that index set to the aforementioned instance method of UITableView.

If you want to delete cells from your table view, follow these steps:

  1. First, delete the cell(s) from your data source. Again, it doesn’t matter if you are using Core Data, a simple dictionary, array, or anything else. The important thing is to delete the objects that represent the table view cells from your data source.

  2. Now, in order to delete the cells that correspond to your data objects, invoke the deleteRowsAtIndexPaths:withRowAnimation: instance method of your table view. The first parameter that you have to pass to this method is an array of type NSArray that must contain objects of type NSIndexPath, with each index path rep‐ resenting one cell in the table view. Each index path has a section and a row and can be constructed using the indexPathForRow:inSection: class method of NSIndexPath class.

First things first. Let’s define our view controller:

#import "ViewController.h"

static NSString *CellIdentifier = @"NumbersCellIdentifier";

@interface ViewController () <UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, strong) UITableView *tableViewNumbers;
@property (nonatomic, strong) NSMutableDictionary *dictionaryOfNumbers;
@property (nonatomic, strong) UIBarButtonItem *barButtonAction;
@end

Now let’s define the static string keys for our arrays inside the data source dictionary:

static NSString *SectionOddNumbers = @"Odd Numbers";
static NSString *SectionEvenNumbers = @"Even Numbers";

We now need to populate our data source dictionary with values before we create our table view. Here is the simple getter method that will take care of populating the dic‐ tionary for us:

- (NSMutableDictionary *) dictionaryOfNumbers{

    if (_dictionaryOfNumbers == nil){
        NSMutableArray *arrayOfEvenNumbers =
        [[NSMutableArray alloc] initWithArray:@[
                                                @0,
                                                @2,
                                                @4,
                                                @6,
                                                ]];

        NSMutableArray *arrayOfOddNumbers =
        [[NSMutableArray alloc] initWithArray:@[
                                                @1,
                                                @3,
                                                @5,
                                                @7,
                                                ]];

        _dictionaryOfNumbers =
        [[NSMutableDictionary alloc]
         initWithDictionary:@{
                              SectionEvenNumbers : arrayOfEvenNumbers,
                              SectionOddNumbers : arrayOfOddNumbers,
                              }];

    }
    return _dictionaryOfNumbers;
}

So far, so good? As you can see, we have two arrays, each of which contains some num‐ bers (one odd and the other even numbers) and we associate them with the SectionE venNumbers and SectionOddNumbers keys that we declared before in the implementa‐ tion file of our view controller. Now let’s go ahead and instantiate our table view:

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.barButtonAction =
    [[UIBarButtonItem alloc]
     initWithTitle:@"Delete Numbers > 2"
     style:UIBarButtonItemStylePlain
     target:self
     action:@selector(deleteNumbersGreaterThan2:)];

    [self.navigationItem setRightBarButtonItem:self.barButtonAction
                                      animated:NO];

    self.tableViewNumbers = [[UITableView alloc]
                             initWithFrame:self.view.frame
                             style:UITableViewStyleGrouped];

    [self.tableViewNumbers registerClass:[UITableViewCell class]
                  forCellReuseIdentifier:CellIdentifier];

    self.tableViewNumbers.autoresizingMask =
        UIViewAutoresizingFlexibleWidth |
        UIViewAutoresizingFlexibleHeight;

    self.tableViewNumbers.delegate = self;
    self.tableViewNumbers.dataSource = self;

    [self.view addSubview:self.tableViewNumbers];

}

The next thing we need to do is populate our table view with data inside our data source dictionary:

- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView{

    return self.dictionaryOfNumbers.allKeys.count;

}

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

    NSString *sectionNameInDictionary =
        self.dictionaryOfNumbers.allKeys[section];

    NSArray *sectionArray = self.dictionaryOfNumbers[sectionNameInDictionary];
    return sectionArray.count;

}

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

    UITableViewCell *cell = nil;

    cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier
                                           forIndexPath:indexPath];

    NSString *sectionNameInDictionary =
        self.dictionaryOfNumbers.allKeys[indexPath.section];

    NSArray *sectionArray = self.dictionaryOfNumbers[sectionNameInDictionary];

    NSNumber *number = sectionArray[indexPath.row];

    cell.textLabel.text = [NSString stringWithFormat:@"%lu",
                             (unsigned long)[number unsignedIntegerValue]];

    return cell;

}

- (NSString *) tableView:(UITableView *)tableView
 titleForHeaderInSection:(NSInteger)section{

    return self.dictionaryOfNumbers.allKeys[section];

}

Our navigation button is linked to the deleteOddNumbersSection: selector. This is a method we are going to code now. The purpose of this method, as its name implies, is to find the section that corresponds to all odd numbers in our data source and the table view and remove that section from both of these. Here is how we will do it:

- (void) deleteOddNumbersSection:(id)paramSender{

    /* First remove the section from our data source */
    NSString *key = SectionOddNumbers;
    NSInteger indexForKey = [[self.dictionaryOfNumbers allKeys]
                             indexOfObject:key];

    if (indexForKey == NSNotFound){
        NSLog(@"Could not find the section in the data source.");
        return;
    }
    [self.dictionaryOfNumbers removeObjectForKey:key];

    /* Then delete the section from the table view */
    NSIndexSet *sectionToDelete = [NSIndexSet indexSetWithIndex:indexForKey];
    [self.tableViewNumbers deleteSections:sectionToDelete
                         withRowAnimation:UITableViewRowAnimationAutomatic];

    /* Finally, remove the button from the navigation bar
     as it is not useful any longer */
    [self.navigationItem setRightBarButtonItem:nil animated:YES];

}

We now know how to delete sections from table views. Let’s move to deleting cells. We are going to change the functionality of our navigation bar button so that when it is pressed, it will delete all cells in all sections of our table view with a numerical value greater than 2. That includes all odd and even numbers greater than 2. So let’s change our navigation bar button item in the viewDidLoad method of our view controller:

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.barButtonAction =
    [[UIBarButtonItem alloc]
     initWithTitle:@"Delete Numbers > 2"
     style:UIBarButtonItemStylePlain
     target:self
     action:@selector(deleteNumbersGreaterThan2:)]; //change the selector
...
...
}

The navigation bar button is now connected to the deleteNumbersGreaterThan2: selector. This is a method that we have to implement in our view controller, but before jumping into coding it straightaway, let’s first define what this method should do:

  1. Find both arrays of odd and even numbers in our data source and grab the index paths (of type NSIndexPath) of those numbers that are greater than 2. We will use these index paths to later delete the corresponding cells from the table view.

  2. Delete all the numbers greater than 2 from our data source, in both the even and odd number dictionaries.

  3. Delete the relevant cells from the table view. We collected the index paths of these cells in the first step.

- (void) deleteNumbersGreaterThan2:(id)paramSender{

    NSMutableArray *arrayOfIndexPathsToDelete =
        [[NSMutableArray alloc] init];

    NSMutableArray *arrayOfNumberObjectsToDelete =
        [[NSMutableArray alloc] init];

    /* Step 1: gather the objects we have to delete from our data source
     and their index paths */
    __block NSUInteger keyIndex = 0;
    [self.dictionaryOfNumbers enumerateKeysAndObjectsUsingBlock:
     ^(NSString *key, NSMutableArray *object, BOOL *stop) {

         [object enumerateObjectsUsingBlock:
          ^(NSNumber *number, NSUInteger numberIndex, BOOL *stop) {

              if ([number unsignedIntegerValue] > 2){

                  NSIndexPath *indexPath =
                  [NSIndexPath indexPathForRow:numberIndex
                                     inSection:keyIndex];

                  [arrayOfIndexPathsToDelete addObject:indexPath];
                  [arrayOfNumberObjectsToDelete addObject:number];
              }

          }];

         keyIndex++;
     }];

    /* Step 2: delete the objects from the data source */
    if ([arrayOfNumberObjectsToDelete count] > 0){
        NSMutableArray *arrayOfOddNumbers =
            self.dictionaryOfNumbers[SectionOddNumbers];

        NSMutableArray *arrayOfEvenNumbers =
            self.dictionaryOfNumbers[SectionEvenNumbers];

        [arrayOfNumberObjectsToDelete enumerateObjectsUsingBlock:
         ^(NSNumber *numberToDelete, NSUInteger idx, BOOL *stop) {
             if ([arrayOfOddNumbers indexOfObject:numberToDelete]
                    != NSNotFound){
                 [arrayOfOddNumbers removeObject:numberToDelete];
             }
             if ([arrayOfEvenNumbers indexOfObject:numberToDelete]
                    != NSNotFound){
                 [arrayOfEvenNumbers removeObject:numberToDelete];
             }
         }];
    }

    /* Step 3: delete the cells that correspond to the objects */
    [self.tableViewNumbers
     deleteRowsAtIndexPaths:arrayOfIndexPathsToDelete
     withRowAnimation:UITableViewRowAnimationAutomatic];

    [self.navigationItem setRightBarButtonItem:nil animated:YES];

}
Clone this wiki locally