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 ofUITableView
on your table view. The first parameter that you need to pass to this method is of typeNSIndexSet
, and this object can be instantiated using theindexSetWithIndex:
class method ofNSIndexSet
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 theindexSetWithIndexesInRange:
class method ofNSIndexSet
to create the index set using a range, and pass that index set to the aforementioned instance method ofUITableView
.
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 typeNSArray
that must contain objects of typeNSIndexPath
, with each index path representing one cell in the table view. Each index path has a section and a row and can be constructed using theindexPathForRow:inSection:
class method ofNSIndexPath
class.
In your UI code, sometimes you might need to delete cells and/or
sections. For instance, you might have a switch (of type UISwitch
; see Recipe 1.2), and when the
switch is turned on by the user, you might want to insert a few rows
into your table view. After the switch is turned off by the user, you
will then want to delete those rows. It’s not always table view cells
(rows) that you have to delete. Sometimes you might need to delete a
whole section or a few sections simultaneously from your table view. The
key for deleting cells and sections from table views is to first delete
the data corresponding to those cells/sections from your data source,
and then call the appropriate deletion method on the
table view. After the deletion method finishes, the table view will
refer back to its data source object. If the number of cells/sections in
the data source doesn’t match the number of cells/sections in the table
view after the deletion is complete, your app will crash. But don’t
worry—if you ever do make this mistake, the debug text that gets printed
to the console is descriptive enough to point you in the right
direction.
Let’s have a look at how we can delete sections from a table view. For this recipe, we will display a table view on a view controller that is displayed inside a navigation controller. Inside the table view, we will display two sections, one for odd numbers and another for even numbers. We will display only 1, 3, 5, and 7 for odd numbers and 0, 2, 4, and 6 for even numbers. For the first exercise, we are going to place a navigation bar button on our navigation bar and make that button responsible for deleting the section with odd numbers in it. Figure 4-15 shows what we want the results to look like.
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
The tableViewNumbers
property
is our table view. The barButtonAction
property is the
bar button that we’ll display on the
navigation bar. Last but not least, the dictionary
OfNumbers
property is our data source for the
table view. In this dictionary, we will place
two values of type NSMutableArray
that contain our numbers of type NS
Number
. They are mutable arrays, so that,
later in this chapter, we will be able to delete them individually from
the arrays in the dictionary. We will keep the keys for these arrays in
our dictionary as static values in the implementation file of our view
controller, so that we can later simply extract them from the dictionary
using the static keys (if the keys were not static, finding our arrays
in the dictionary would have to be done with string comparison, which is
slightly more time-consuming than simply associating the object with a
static key that doesn’t change during the lifetime of our view
controller). 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"
;
@implementation
ViewController
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 dictionary 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 numbers (one odd and the other even numbers) and we
associate them with the SectionEvenNumbers
and SectionOddNumbers
keys that we declared before
in the implementation 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 Odd Numbers"
style:
UIBarButtonItemStylePlain
target:
self
action:
@selector
(
deleteOddNumbersSection
:
)];
[
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
];
}
Simple enough. Now, when the user presses the navigation bar
button, the Odd Numbers section will disappear from the table view. You
can note that there is an animation that gets committed on the table
view while the section is being deleted. This is because of the UITableViewRowAnimationAutomatic
animation
type that we are passing to the withRowAnimation:
parameter of the
deleteSections:withRowAnimation:
method of our table view. Now run the app in iOS Simulator and select
Debug → Toggle Slow Animations. Then
attempt to press the navigation bar button and see what happens. You can
see the deletion animation in slow motion. It’s neat, isn’t it? After
the deletion is completed, our app will look similar to Figure 4-16.
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
:
)];
[
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
];
}
Figure 4-17 shows the results of our app running in iPhone Simulator.
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.
Remove the navigation bar button, since it won’t be of any use after the relevant cells have been deleted from the data source and the table view. Alternatively, if you want, you could just disable this button—but I think removing the button provides a better user experience, since a disabled button is really of no use to the user.
-
(
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
];
}
After the user presses the button on the navigation bar, all cells containing a number greater than 2 will be deleted from our data source, and the table view and our app will look like Figure 4-18.
Get iOS 7 Programming Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.