I don't know if autoconfigurable can be found in the dictionary, but I am going to use it anyway because it best describes what we are going to do in this episode. In the previous episode, we refactored the SettingsViewController class. In the tableView(_:cellForRowAt:) method, we create an object that conforms to the SettingsPresentable protocol. The settings view controller manually configures each table view cell, using a view model. Why can't the table view cell configure itself? Can we make it autoconfigurable?
The idea is simple. The table view cell asks the view model for the values it needs and populates itself with data. This is very different from handing a model to a view, which is something we don't intend to do. The table view cell won't know about the model. It will simply use the interface of the SettingsPresentable protocol.
Updating the Settings Table View Cell
To make this work, we need to make some changes to the SettingsTableViewCell class. Open SettingsTableViewCell.swift and define a method with name configure(with:). The method accepts one argument of type SettingsPresentable. In the body of the method, the table view cell sets the text property of its mainLabel property and updates its accessoryType property.
SettingsTableViewCell.swift
import UIKit
class SettingsTableViewCell: UITableViewCell {
// MARK: - Properties
@IBOutlet var mainLabel: UILabel!
// MARK: - Initialization
override func awakeFromNib() {
super.awakeFromNib()
// Configure Cell
selectionStyle = .none
}
// MARK: - Public API
func configure(with presentable: SettingsPresentable) {
// Configure Main Label
mainLabel.text = presentable.text
// Set Accessory Type
accessoryType = presentable.accessoryType
}
}
Updating the Settings View Controller
All that is left for us to do is updating the SettingsViewController class. Open SettingsViewController.swift and navigate to the tableView(_:cellForRowAt:) method. The settings view controller no longer needs to configure the table view cell. Instead, it invokes the configure(with:) method of the table view cell and passes it the SettingsPresentable object. I am sure you agree that this looks quite nice.
SettingsViewController.swift
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
// Configure Cell
cell.configure(with: viewModel)
return cell
}
Notice that the settings view controller is still involved, but its role is very limited. By implementing the configure(with:) method and passing a view model to the table view cell, we have slightly deviated from the Model-View-ViewModel pattern we discussed in the introduction of this series.
But that is fine. Views need to be dumb. They shouldn't know what they are displaying and that still applies to the SettingsTableViewCell class. The table view cell only uses the interface of the SettingsPresentable protocol to configure itself.
Protocol-Oriented Programming
I want to highlight the role of the SettingsPresentable protocol in this story. The SettingsPresentable protocol serves two purposes. The most obvious task of the SettingsPresentable protocol is defining an interface. Because the view models we defined earlier conform to this protocol, the SettingsTableViewCell class only needs to have the ability to handle an object of type SettingsPresentable.
The SettingsPresentable protocol performs another important but less obvious task. It adds a layer of abstraction. The SettingsPresentable protocol ensures that the SettingsTableViewCell class doesn't need to know about the view models we defined. That is one of the key benefits of protocol-oriented programming.
What's Next?
The settings view controller is a simple controller, but I hope you can see the potential of the Model-View-ViewModel pattern in simplifying controllers. The settings view controller is a focused controller. All it does is manage its view and subviews, and handle user interaction. That is the primary role of every controller and that applies to both MVVM and MVC.
In the next episode, we apply what we have learned in the past two episodes to the week view controller.