Separate UITableView/UICollectionView DataSource from a View Controller in Swift

View controllers can get really massive in some cases when you place the data source and delegate methods inside it when using a tableView or a collectionView. To overcome that you can separate them out. In this article we will take a look at how we can separate the data source of tableView.

A data source is an object that provides data to a UI element, such as a table view or collection view. The data source acts as the source of truth for the data that is displayed in the UI, and is responsible for providing the data to the user interface when requested.

A common approach for implementing data sources in Swift is to create a separate class for each UI element that requires a data source. This class would conform to the appropriate protocol for the UI element, such as UITableViewDataSource or UICollectionViewDataSource, and would provide the necessary methods to manage the data and populate the user interface element. Here is an example of how a data source class might be implemented:

class UserTableViewDataSource: NSObject, UITableViewDataSource {
 
  // MARK: - Properties 
  private let users: [User] 
  
  // MARK: - Initialization 
  init(users: [User]) { 
    self.users = users 
  } 

  // MARK: - UITableViewDataSource 
  func numberOfSections(in tableView: UITableView) -> Int { 
    return 1 
  } 

  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
    return users.count 
  } 

  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    let user = users[indexPath.row] 
    let cell = tableView.dequeueReusableCell(withIdentifier: "UserTableViewCell", for: indexPath) as! UserTableViewCell 
    cell.configure(withUser: user) 
    return cell 
  } 
}

In the above example, the UserTableViewDataSource class is a data source for a table view that displays a list of users. It has a property called users that holds the data that is displayed in the table view, and it conforms to the UITableViewDataSource protocol to provide the necessary methods for managing the data and populating the table view.

The numberOfSections(in:) and (_:numberOfRowsInSection:) methods are used to tell the table view how many sections and rows it should display. The tableView(_:cellForRowAt:) method is called by the table view to obtain the cell for a particular row. This method dequeues a reusable cell, configures it with the user data, and returns it to the table view.

To use this data source with a table view, you would set the table view’s dataSource property to an instance of the UserTableViewDataSource class, and provide the data that should be displayed in the table view.

For example:

let users = [
  User(name: "Alice", age: 24), 
  User(name: "Bob", age: 26)
] 
let dataSource = UserTableViewDataSource(users: users) tableView.dataSource = dataSource

This would set the tableView's data source to the UserTableViewDataSource instance, and the table view would display a list of the users provided in the users array.

For further details you can refer to Apple’s official documentation about UITableView and UICollectionView data sources.

Also read: Weak, Strong and Unowned in Swift