Шаблон делегирования
Самый важный и частый вопрос на собеседованиях.
Делегирование — это шаблон проектирования, согласно которому при возникновении конкретного события от одного объекта другому отправляются сообщения. На Swift он применяется с помощью Protocol.
Пример шаблона делегирования с Protocol:
// SomeProtocol.swift
protocol SomeProtocol{ //
func modifyTextToLabel(someText: String)
}Protocol: создан SomeProtocol.swift и добавлен метод для изменения текста на метку ViewController.
// FirstViewController.swift
class FirstViewController: UIViewController{
private lazy var someLabel: UILabel = {
let label = UILabel()
label.frame = CGRect(x: 100, y: 150, width: 100, height: 50)
label.text = "Default"
return label
}()
private lazy var someButton: UIButton = {
let button = UIButton(frame: CGRect(x: 100, y: 200, width: 100, height: 50))
button.setTitle("Press ME!", for: .normal)
button.backgroundColor = .red
button.addTarget(self, action: #selector(handleButtonTapped), for: .touchUpInside)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(someLabel)
view.addSubview(someButton)
}
}ViewController: создан FirstViewController и с помощью «ленивых» переменных добавлены метка и кнопка. То есть инициализация или вычисление отложены до тех пор, пока не понадобятся.
// SecondViewController.swift
class SecondViewController: UIViewController, UITextFieldDelegate {
lazy var someTextField: UITextField = {
let textField = UITextField(frame: CGRect(x: 100, y: 100, width: 100, height: 60))
textField.placeholder = "Enter Text"
textField.keyboardType = .default
return textField
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(someTextField)
someTextField.delegate = self
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
return true
}
}ViewController: создан другой ViewController — SecondViewController и добавлено текстовое поле для получения пользовательского ввода. someTextField соответствует протоколу UITextFieldDelegate.
class FirstViewController: UIViewController, SomeProtocol {
func modifyTextToLabel(someText: String) {
self.someLabel.text = someText
}
}
FirstViewController соответствует SomeProtocol и унаследовал требования, или методы.
class SecondViewController: UIViewController, UITextFieldDelegate {
weak var delegate: SomeProtocol? // слабая переменная во избежание циклов сохранения
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if textField.hasText {
delegate?.modifyTextToLabel(someText: textField.text ?? "")
navigationController?.popToRootViewController(animated: true)
return true
}
return false
}
}В ПЕРЕМЕННОЙ «DELEGATE» СОДЕРЖИТСЯ SOMEPROTOCOL, ОНА КАК ДЕЛЕГАТ МЕЖДУ SECONDVIEWCONTROLLER И FIRSTVIEWCONTROLLER. ПРИСВОЕНА СЛАБОЙ ССЫЛКЕ ВО ИЗБЕЖАНИЕ ЦИКЛОВ СОХРАНЕНИЯ.
Здесь modifyTextToLabel — это метод делегата для передачи данных из SecondViewController в FirstViewController. Поэтому текст этого someLabel в FirstViewController изменится.
А ПОЧЕМУ В PROTOCOL ИСПОЛЬЗУЕТСЯ ANYOBJECT?
Читать