Dynamic table views

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:

Dynamic table views

Note

The string that you enter into the Reuse Identifier box is case sensitive.

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:

Dynamic table views

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.

Data sources

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.

Tip

If you have a complicated data set, you can group the data into sections using the numberOfSectionsInTableView() method.

Delegates

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.

Bringing it all together

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:

Bringing it all together

Our app in the iPhone 4s simulator

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.116.8.110