Tips and Tricks

Using didSet Property Observers to Configure Outlets

Download Your Free Copy of
The Missing Manual
for Swift Development

The Guide I Wish I Had When I Started Out

Join 20,000+ Developers Learning About Swift Development

Download Your Free Copy

I don't like long or complex viewDidLoad() methods. The viewDidLoad() method of a view controller should be short and easy to understand. The tip I am about to share with you helps declutter the viewDidLoad() method of the view controllers in your projects.

Decluttering View Did Load

Developers tend to configure the outlets of a view controller in the viewDidLoad() method. This isn't wrong, but it can easily lead to a long or complex viewDidLoad() method. A few years ago, I picked up a tip that leverages property observers to declutter the viewDidLoad() method. It has another important benefit I explain in a moment.

Take a look at the following code snippet. The NotesViewController class defines two outlets, tableView of type UITableView and messageLabel of type UILabel.

import UIKit

internal final class NotesViewController: UIViewController {

    // MARK: - Properties

    @IBOutlet private var tableView: UITableView!

    // MARK: -

    @IBOutlet private var messageLabel: UILabel!

    // MARK: - View Life Cycle

    override func viewDidLoad() {
        super.viewDidLoad()

        // Configure Table View
        tableView.delegate = self
        tableView.dataSource = self
        tableView.showsVerticalScrollIndicator = false

        // Register Note Table View Cell
        tableView.register(NoteTableViewCell.self, forCellReuseIdentifier: NoteTableViewCell.reuseIdentifier)

        // Configure Message Label
        messageLabel.numberOfLines = 0
        messageLabel.font = .systemFont(ofSize: 15.0)
        messageLabel.text = NSLocalizedString("notes_message_no_notes", comment: "")
    }

}

The table view and the label are configured in the viewDidLoad() method of the notes view controller. We have several options to optimize the implementation of the NotesViewController class. We could configure the outlets in the storyboard or XIB file. While that is an option, I avoid that as much as possible. Configuring user interface elements in code makes it easier to understand how the user interface is set up and configured. It also adds flexibility. Updating a user interface element is as simple as updating its configuration in the view controller.

Another option is to create a helper method in which the user interface elements are configured. By invoking the helper method in viewDidLoad(), we keep the implementation of viewDidLoad() short and readable.

Using Property Observers to Configure Outlets

The option I have been using for several years is even better and far more elegant. We define a didSet property observer for each outlet and use the didSet property observer to configure the user interface element. Take a look at the updated implementation.

import UIKit

internal final class NotesViewController: UIViewController {

    // MARK: - Properties

    @IBOutlet private var tableView: UITableView! {
        didSet {
            // Configure Table View
            tableView.delegate = self
            tableView.dataSource = self
            tableView.showsVerticalScrollIndicator = false

            // Register Note Table View Cell
            tableView.register(NoteTableViewCell.self, forCellReuseIdentifier: NoteTableViewCell.reuseIdentifier)
        }
    }

    // MARK: -

    @IBOutlet private var messageLabel: UILabel! {
        didSet {
            // Configure Message Label
            messageLabel.numberOfLines = 0
            messageLabel.font = .systemFont(ofSize: 15.0)
            messageLabel.text = NSLocalizedString("notes_message_no_notes", comment: "")
        }
    }

}

Because we move the configuration of each outlet to its didSet property observer, we can remove the viewDidLoad() method. We don't need a helper method to configure the outlets and, more important, the declaration and the configuration of each outlet are grouped together. This makes it easy to read and understand the implementation of the NotesViewController class.

Each outlet is set only once, which means that its didSet property observer is also invoked only once. I really enjoy using this pattern to clean up the view controllers of a project. Give it a try to see if you like it.

Download Your Free Copy of
The Missing Manual
for Swift Development

The Guide I Wish I Had When I Started Out

Join 20,000+ Developers Learning About Swift Development

Download Your Free Copy
Next Episode "Why You Should Default to Private Outlets"