Conform to the UITableViewDataSource
protocol in an object
and assign that object to the dataSource
property of a table view.
Create an object that conforms to the UITableViewDataSource
protocol and assign it
to a table view instance. Then, by responding to the data source
messages, provide information to your table view. For this example,
let’s go ahead and declare the .m
file of our view controller, which will later create a table view on its
own view, in code:
#import "ViewController.h"
static
NSString
*
TableViewCellIdentifier
=
@"MyCells"
;
@interface
ViewController
()
<
UITableViewDataSource
>
@property
(
nonatomic
,
strong
)
UITableView
*
myTableView
;
@end
The TableViewCellIdentifier
contains our cell
identifiers as a static string variable. Each cell, as you will learn
soon, can have an identifier, which is great for reusing cells. For now,
think about this as a unique identifier for all the cells in our table
view, nothing more.
In the viewDidLoad
method
of our view controller, we create the table view and assign our view
controller as its data source:
-
(
void
)
viewDidLoad
{
[
super
viewDidLoad
];
self
.
myTableView
=
[[
UITableView
alloc
]
initWithFrame
:
self
.
view
.
bounds
style:
UITableViewStylePlain
];
[
self
.
myTableView
registerClass
:
[
UITableViewCell
class
]
forCellReuseIdentifier:
TableViewCellIdentifier
];
self
.
myTableView
.
dataSource
=
self
;
/* Make sure our table view resizes correctly */
self
.
myTableView
.
autoresizingMask
=
UIViewAutoresizingFlexibleWidth
|
UIViewAutoresizingFlexibleHeight
;
[
self
.
view
addSubview
:
self
.
myTableView
];
}
Everything is very simple in this code snippet except for the
registerClass:forCellReuseIdentifier:
method that we are calling on the instance of our table view. What does
this method do, you ask? The registerClass
parameter of this method simply
takes a class name that denotes the type of object that you want your
table view to load when it renders each cell. Cells inside a table view
all have to be direct or indirect ancestors of the UITableViewCell
class. This class on its own
provides a lot of functionalities to programmers, but if you want to
extend this class, you can simply subclass it and add your new
functionalities to your own class. So going back to the registerClass
parameter of the aforementioned
method, you have to pass the class name of your cells to this parameter
and then pass an identifier to the forCellReuseIdentifier
parameter. The
reason behind associating table view cell classes with
identifiers is that later, when you populate your table view, you can
simply pass the same identifier to the table view’s dequeueReusableCellWithIdentifier:forIndexPath:
method and have the table view instantiate the cell for you if one
cannot be reused. This is great stuff, because in previous versions of
the iOS SDK, programmers had to instantiate these cells themselves if a
previous and reusable cell could not be retrieved from the table
view.
Now we need to make sure our table view responds to the @required
methods of the UITableViewDataSource
protocol. Press the
Command+Shift+O key combination on your keyboard, type this protocol
name in the dialog, and then press the Enter key. This will show you the
required methods for this protocol.
The UITableView
class defines a
property called dataSource
. This is
an untyped object that must conform to the UITableViewDataSource
protocol. Every time a
table view is refreshed and reloaded using the reloadData
method, the table view will call
various methods in its data source to find out about the data you intend
to populate it with. A table view data source can implement three
important methods, two of which are mandatory for every data
source:
numberOfSectionsInTableView:
This method allows the data source to inform the table view of the number of sections that must be loaded into the table.
tableView:numberOfRowsInSection:
This method tells the view controller how many cells or rows have to be loaded for each section. The section number is passed to the data source in the
numberOfRowsInSection
parameter. The implementation of this method is mandatory in the data source object.tableView:cellForRowAtIndexPath:
This method is responsible for returning instances of the
UITableViewCell
class as rows that have to be populated into the table view. The implementation of this method is mandatory in the data source object.
So let’s go ahead and implement these methods in our view controller, one by one. First, let’s tell the table view that we want it to render three sections:
-
(
NSInteger
)
numberOfSectionsInTableView:
(
UITableView
*
)
tableView
{
if
([
tableView
isEqual
:
self
.
myTableView
]){
return
3
;
}
return
0
;
}
Then we tell the table view how many rows we want it to render for each section:
-
(
NSInteger
)
tableView:
(
UITableView
*
)
tableView
numberOfRowsInSection:
(
NSInteger
)
section
{
if
([
tableView
isEqual
:
self
.
myTableView
]){
switch
(
section
){
case
0
:{
return
3
;
break
;
}
case
1
:{
return
5
;
break
;
}
case
2
:{
return
8
;
break
;
}
}
}
return
0
;
}
So up to now, we have asked the table view to render three
sections with three rows in the first, five rows in the second, and
eight rows in the third section. What’s next? We have to return
instances of UITableViewCell
to the
table view—the cells that we want the table view to render:
-
(
UITableViewCell
*
)
tableView:
(
UITableView
*
)
tableView
cellForRowAtIndexPath:
(
NSIndexPath
*
)
indexPath
{
UITableViewCell
*
cell
=
nil
;
if
([
tableView
isEqual
:
self
.
myTableView
]){
cell
=
[
tableView
dequeueReusableCellWithIdentifier:
TableViewCellIdentifier
forIndexPath:
indexPath
];
cell
.
textLabel
.
text
=
[
NSString
stringWithFormat
:
@"Section %ld, Cell %ld"
,
(
long
)
indexPath
.
section
,
(
long
)
indexPath
.
row
];
}
return
cell
;
}
Now if we run our app in iPhone Simulator, we will see the results of our work (Figure 4-2).
When a table view is reloaded or refreshed, it queries its data
source through the UITableViewDataSource
protocol, asking for
various bits of information. Among the important
methods previously mentioned, the table view will first ask for the
number of sections. Each section is responsible for holding rows or
cells. After the data source specifies the number of sections, the table
view will ask for the number of rows that have to be loaded into each
section. The data source gets the zero-based index of each section and,
based on this, can decide how many cells have to be loaded into
each section.
The table view, after determining the number of cells in the
sections, will continue to ask the data source about the view that will
represent each cell in each section. You can allocate instances of the
UITableViewCell
class and return them
to the table view. There are, of course, properties that can be set for
each cell, including the title, subtitle, and color of each cell, among
other properties.
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.