Delegate в Swift

Давайте рассмотрим более подробный пример использования делегатов в iOS, чтобы лучше понять, как это работает на практике. Мы создадим простое приложение с двумя контроллерами: один контроллер будет представлять экран с кнопкой, а другой контроллер будет выполнять некоторые действия, когда кнопка будет нажата.

Полный пример использования делегатов:

Шаг 1: Определение протокола

Протокол — это "контракт", который описывает, какие методы должен реализовать класс, чтобы стать делегатом. В нашем случае протокол будет содержать один метод, который будет вызван при нажатии кнопки.

protocol ButtonDelegate: AnyObject {
    func didPressButton()
}

Шаг 2: Создание первого контроллера (с кнопкой)

Первый контроллер будет содержать кнопку, и когда пользователь нажимает на эту кнопку, он будет уведомлять делегата о том, что произошло событие.

import UIKit

class ButtonViewController: UIViewController {

    // Свойство делегата
    weak var delegate: ButtonDelegate?

    override func viewDidLoad() {
        super.viewDidLoad()

        // Настраиваем кнопку
        let button = UIButton(type: .system)
        button.setTitle("Нажми меня", for: .normal)
        button.frame = CGRect(x: 100, y: 100, width: 200, height: 50)
        button.addTarget(self, action: #selector(buttonPressed), for: .touchUpInside)
        
        view.addSubview(button)
        view.backgroundColor = .white
    }

    // Метод, который будет вызван при нажатии кнопки
    @objc func buttonPressed() {
        // Уведомляем делегата о том, что кнопка была нажата
        delegate?.didPressButton()
    }
}

Шаг 3: Создание второго контроллера (делегата)

Второй контроллер будет принимать на себя роль делегата и реализовывать метод didPressButton, чтобы обрабатывать событие нажатия кнопки.

import UIKit

class AnotherViewController: UIViewController, ButtonDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        let buttonVC = ButtonViewController()
        buttonVC.delegate = self // Назначаем делегата

        // Добавляем контроллер с кнопкой как дочерний контроллер
        addChild(buttonVC)
        view.addSubview(buttonVC.view)
        buttonVC.didMove(toParent: self)
        
        view.backgroundColor = .lightGray
    }

    // Реализация метода делегата
    func didPressButton() {
        print("Кнопка нажата во втором контроллере")
        
        // Допустим, мы показываем алерт при нажатии кнопки
        let alert = UIAlertController(title: "Уведомление", message: "Кнопка была нажата", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "ОК", style: .default, handler: nil))
        present(alert, animated: true, completion: nil)
    }
}

Подробное объяснение:

  1. Протокол ButtonDelegate:

    • Протокол описывает метод, который должен реализовать любой делегат (в нашем случае это didPressButton).
    • Мы используем модификатор AnyObject, чтобы делегат мог быть слабым (weak), что помогает избежать циклов удержания.
  2. Контроллер с кнопкой (ButtonViewController):

    • Этот контроллер содержит кнопку и свойство delegate, которое ссылается на объект, реализующий протокол ButtonDelegate.
    • Когда кнопка нажата, вызывается метод delegate?.didPressButton(), если делегат установлен.
  3. Контроллер делегата (AnotherViewController):

    • Этот контроллер реализует протокол ButtonDelegate и содержит метод didPressButton, который вызывается, когда кнопка в другом контроллере нажата.
    • Здесь мы показываем алерт при срабатывании метода делегата.

Почему это полезно:

  • Гибкость: Делегаты позволяют вам отделить логику обработки событий от их источника. Это полезно, когда один объект должен передать управление другому объекту.
  • Модульность: Использование делегатов помогает сделать код более модульным и переиспользуемым.
  • Отсутствие жесткой связи: Делегаты позволяют передавать события между объектами без необходимости их тесного связывания, что улучшает тестируемость и расширяемость кода.

Как избежать циклов удержания:

Важно помнить о слабых ссылках (weak) при использовании делегатов, так как это помогает предотвратить циклы удержания, где два объекта удерживают друг друга и никогда не освобождаются из памяти. В примере выше мы используем:

Давай рассмотрим более подробный пример использования делегатов в iOS, чтобы лучше понять, как это работает на практике. Мы создадим простое приложение с двумя контроллерами: один контроллер будет представлять экран с кнопкой, а другой контроллер будет выполнять некоторые действия, когда кнопка будет нажата.

weak var delegate: ButtonDelegate?

Эта строка гарантирует, что ButtonViewController не будет удерживать своего делегата, что особенно важно в долгоживущих иерархиях контроллеров.

Дополнительные варианты использования:

  1. UITableView и UICollectionView: Встроенные делегаты используются для управления действиями в таблицах и коллекциях.
  2. Custom Views: Делегаты могут использоваться для передачи событий от пользовательских компонентов (например, кастомных кнопок или слайдеров) к контроллеру.