Dynamic table views were created specifically to show large amounts of data in an efficient manner. Behind the scenes, the system is able to efficiently load and reuse cells in order for the table view to scroll as smoothly as possible. Think of it this way: imagine a stack of 100 cells but imagine that only 10 of those cells are on screen at one time. Instead of filling up your device's memory with all 100 of those cells, the system will instead load just the 10 that you can see plus a few extra to handle any future scrolling. As you scroll down, the memory address that represents the cells that you've scrolled past are added back at the bottom of the table and filled with different information. This may seem complicated, but implementing these features is quite simple.
We placed a new table view controller
onto the canvas to the right of our static table controller
. The most noticeable difference we can see is the section called prototype cells within our table. A prototype cell is simply the template that each cell is going to use while the system creates it. IB adds one prototype cell onto our table by default.
To start, select the prototype cell and change its Style from Custom to Basic. This is identical to how we changed the cell in our static table view example. While the cell is selected, we need to set the reuse identifier on the cell so that the system knows how to access this prototype template. Name it DetailCell:
Now, we need to create the controller for this dynamic table. Create a new file by going to File | New | File. Select Cocoa Touch Class
and press the Next button. In the file details wizard screen, select UITableViewController
in the Subclass Of: select box, and name it ExampleTableViewController
. Save this file in the same location as the rest of the files in your project.
The newly created file will automatically open. Press the Back button in the jump bar to go back to the Main.storyboard
file. We need to associate this newly created controller with our view.
Click on the Table View Controller
button at the top of the view in the canvas and open the Identity Inspector area of the Utility sidebar. In the Class box, enter ExampleTableViewController
and press Enter on the keyboard. You've now associated the view and the controller:
Before we move to the controller that we just created, we need to talk about delegates and data sources and how they allow us to populate a table with items. Select the Connections Inspector in the Utility sidebar. You'll see that two referencing outlets are automatically set: delegate
and dataSource
. This is simply saying that our new controller is now connected to our on screen table via these two connections.
Open up the ExampleTableViewController.swift
file by using the Project Navigator Sidebar or the quick open keyboard shortcut Cmd + Shift + O. You'll notice that there is more boilerplate code inside this file than in previous examples.
By subclasing UITableViewController
in our ExampleTableViewController
class, we've automatically been set up as the data source of the table in our view. By itself, the table view has no idea how many sections or items it needs to display. Something needs to provide this data to it. By declaring that our new class is the dataSource
of our table view, it will ask our ExampleTableViewClass
to provide it a number by calling the method:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // #warning Incomplete implementation, return the number of rows return 0 }
This method let's you return the number of rows (items) in a section. By default, a table view will simply have one section.
Many Cocoa APIs use the delegate pattern as a way of communicating. It's a system in which one object keeps a reference to another object and uses that reference to send messages back and forth. By subclassing UITableViewController
, our ExampleTableViewController
is now set up as the delegate of the tableView
object in our view. What this means is that during the lifecycle of our table view, it will ask its delegate some questions and your table will react according to the answers.
The most important tableView
delegate method that we need to make changes to is actually commented out by default in the file template. Remove the /*
and */
lines from around the following code:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath) // Configure the cell... return cell }
This is where you'll use the prototype cell identifier to create and modify the appearance of each cell. This method will be called once for each cell that the dataSource
tells the table to create.
We can remove a portion of the boilerplate
code that was created by default. Let's simplify our class to just the following:
import UIKit class ExampleTableViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() title = "Noble Gasses" } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 0 } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath) // Configure the cell... return cell } }
Let's add a property to the ExampleTableViewController
class to represent the data model that we will be using to populate the table:
import UIKit
class ExampleTableViewController: UITableViewController {
let nobleGasses = ["Helium", "Neon", "Argon", "Krypton", "Xenon", "Radon"]
override func viewDidLoad() {
super.viewDidLoad()
title = "Noble Gasses"
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {return 0
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath)
// Configure the cell...
return cell
}
}
Now that we have the data model with some values, let's modify the dataSource
methods:
import UIKit
class ExampleTableViewController: UITableViewController {
let nobleGasses = ["Helium", "Neon", "Argon", "Krypton", "Xenon", "Radon"]
override func viewDidLoad() {
super.viewDidLoad()
title = "Noble Gasses"
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return nobleGasses.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath)
// Configure the cell...
return cell
}
}
In the numberOfRowsInSection
, we're returning the length of our data model array. This way, if any new noble gasses are discovered in the future, we will simply have to add a new string to our array and the table will be automatically updated.
Our data source is complete; now we need to modify how each cell looks. We're going to make the following changes to the cellForRowAtIndexPath
delegate method:
import UIKit
class ExampleTableViewController: UITableViewController {
let nobleGasses = ["Helium", "Neon", "Argon", "Krypton", "Xenon", "Radon"]
override func viewDidLoad() {
super.viewDidLoad()
title = "Noble Gasses"
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return nobleGasses.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("DetailCell", forIndexPath: indexPath) as UITableViewCell
if let label = cell.textLabel {
label.text = nobleGasses[indexPath.row]
}
return cell
}
}
This code creates a constant object called cell that's been created using the reuse identifier. Then, after checking to make sure that the textLabel
property isn't nil
, it sets the text of the cell to the proper value from the array (using the indexPath
parameter) and then returns the cell to the table view.
Running the app in the simulator or on your device will now show a list of all of the noble gasses. We've dynamically populated a table view:
18.116.8.110