Skip to content

Delegate ​

Delegate gives one object a focused callback interface implemented by another object. UIKit uses it extensively for table views, text fields, pickers, and navigation.

When it helps in iOS ​

A reusable category picker should report a selected category without knowing which screen presented it or what that screen does next.

Original example: a reusable picker event ​

swift
import UIKit

@MainActor
protocol CategoryPickerDelegate: AnyObject {
    func categoryPicker(_ picker: CategoryPickerViewController, didSelect category: String)
}

final class CategoryPickerViewController: UIViewController {
    weak var delegate: (any CategoryPickerDelegate)?

    func selectCategory(_ category: String) {
        delegate?.categoryPicker(self, didSelect: category)
    }
}

final class ProductEditorViewController: UIViewController, CategoryPickerDelegate {
    private var selectedCategory: String?

    func showPicker() {
        let picker = CategoryPickerViewController()
        picker.delegate = self
        present(picker, animated: true)
    }

    func categoryPicker(_ picker: CategoryPickerViewController, didSelect category: String) {
        selectedCategory = category
        picker.dismiss(animated: true)
    }
}

The picker emits an event; the editor decides how to handle it. weak prevents the presented picker from retaining its presenting controller through the delegate.

Production decisions ​

Choose a delegate when there is one logical owner and possibly several related callbacks. For a single one-shot action, a closure may be simpler. Keep UI callbacks on the main actor, and avoid retaining the picker after dismissal. Do not use a delegate as a global broadcast channel; use observation or a shared state owner for multiple listeners.

Follow the ownership relationship ​

CategoryPickerViewController holds one delegate, typed by the narrow CategoryPickerDelegate protocol. The editor creates and presents the picker, then assigns itself as delegate. When a selection occurs, the picker reports the event and leaves the response to the editor. The delegate is weak because presentation already creates an ownership path from the presenting flow to the picker; a strong reverse path can prolong lifetimes.

From example to a UIKit screen ​

Wire selectCategory(_:) to a table-row selection or collection-cell tap. The editor updates its form model, refreshes its category label, and dismisses the picker. If selection can fail validation, return that outcome through another method or have the editor decide whether to dismiss. Keep delegate methods on the main actor because they drive UI. UIKit data-source and delegate APIs follow similar ownership and callback conventions.

Failure modes and verification ​

A missing delegate silently drops the event, so set it before presenting and test that selection reaches the editor. A delegate fits one logical recipient with several related callbacks. For one one-time result, a closure may be shorter. For many independent recipients, use Multicast Delegate or an observation mechanism. Do not make a picker know about a concrete editor class merely to call one method.

All patterns

Released under the MIT License.