-
Notifications
You must be signed in to change notification settings - Fork 1
DD 4.8. Deleting Cells and Sections from Table Views
In order to delete sections from a table view, follow these steps:
-
First delete the section(s) in your data source, whether you are using a data model like Core Data or a dictionary/array.
-
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:
-
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.
-
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:
-
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.
-
Delete all the numbers greater than 2 from our data source, in both the even and odd number dictionaries.
-
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]; }