Ghostboard pixel

Outsource your UITableViewDataSource!

Outsource your UITableViewDataSource!

It is very common that the controller of an UITableView is also its data source. This is the number one reason why view controllers tend to become very massive. Outsourcing the data source to an object on its own is a better solution.

Hint: This post has been updated to Swift 3 and Xcode 8.

Let’s take a look at an example:

import UIKit

class TableViewController: UITableViewController {
    
    private var movies = [String]()
    
    //MARK: - UIViewController
    override func viewDidLoad() {
        movies = ["Terminator","Back To The Future","The Dark Knight"]
        
        tableView.reloadData()
    }
    
    //MARK: - UITableViewDataSource

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return movies.count
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier")!
        
        cell.textLabel?.text = movies[indexPath.row]
        
        return cell
    }
    
}

The table view displays three cells containing movie titles.  Nevertheless you can see in this simple example that there is already a lot of code in the view controller. If you add all the other stuff a view controller needs to do, it will become massive quickly.

So there is a better solution. We create a class called DataSource and move all the data source methods to that class:

import UIKit

class DataSource: NSObject, UITableViewDataSource {
    
    var movies = [String]()
    
    //MARK: - UITableViewDataSource
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return movies.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier")!
        
        cell.textLabel?.text = movies[indexPath.row]
        
        return cell
    }
    
}

Now, TableViewController just needs to create an instance of this object and set it as the table view’s data source:

import UIKit

class TableViewController: UITableViewController {
    
    private let dataSource = DataSource()
    
    //MARK: - UITableViewDataSource
    override func viewDidLoad() {
       
        dataSource.movies = ["Terminator","Back To The Future","The Dark Knight"]
        tableView.dataSource = dataSource

    }
}

The view controller is cleaned up now!

More generally, this method works not only with table views but with all views that need a data source, like UICollectionView  or a view you have written on your own.

Video

Resources:

Title Image: @ enzozo / shutterstock.com