Механизм Target-Action в программировании на Swift

Target-Action — это механизм в iOS, который используется для вызова определенной функции для объекта. Он широко применяется во многих фреймворках и библиотеках iOS. Давайте узнаем, как именно он работает.

Что такое Target-Action?

Рассмотрим идею о том, что программирование — это не что иное, как способ отдавать команды объектам. Мы даем команды объектам и отвечаем на взаимодействие с пользователем. В итоге у нас получается приложение.

Вот одна из таких команд:

bob.kicks(ball)

В приведенном выше коде функция kicks() вызывается для объекта bob и принимает один параметр ball. Боб бьет по мячу.

Представьте, что мы создаем приложение с одной кнопкой. Имя переменной button и тип — UIButton. Когда пользователь нажимает на кнопку, мы хотим выполнить определенную функцию с именем fireworks(). Вот где на помощь приходит Target-Action.

Сначала мы создаем кнопку и устанавливаем для нее текст:

let button = UIButton(type: .plain)
button.setTitle("Феерверки запущены!", for: .normal)

Затем мы используем механизм целевого действия:

button.addTarget(self, action: #selector(fireworks), for: .touchUpInside)

В этой строке кода происходит несколько вещей. Мы вызываем функцию addTarget(_:action:for:) с 3 параметрами. Когда происходит событие .touchUpInside, мы выполняем функцию fireworks() для объекта self.

Вот функция fireworks():

@objc func fireworks() {
    print("Бум!")
}

Константа .touchUpInside происходит от структуры UIControl.Event, которая является частью класса UIControl. Структура UIControl.Event определяет множество управляющих событий, например .valueChanged, .editingDidEnd и .touchDown. Событие .touchUpInside используется для отслеживания взаимодействий на кнопку. Когда вы поднимаете палец после касания, запускается событие .touchUpInside.

Что такое self?

Ключевое слово self используется для ссылки на экземпляр текущего класса.

Давайте посмотрим на пример. Сначала мы создаем класс:

class Vehicle {
    var wheels = 0
    var position = 0
}

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

func drive(to position: Int) {
    self.position = position
}

В приведенном выше коде мы используем self, чтобы различать свойство position и параметр position.

Но есть и другое применение self. Вы можете передать его в своем коде, как и любое другое значение или ссылку:

button.addTarget(self, action: #selector(fireworks), for: .touchUpInside)

С помощью приведенного выше кода вы передаете self к button. У button теперь есть ссылка на текущий экземпляр класса. Теперь button может использовать эту ссылку для вызова функции fireworks() для объекта, на который ссылается self.

Целевой объект обычно является контроллером представления. Мы добавили кнопку к контроллеру представления, а также функцию, и мы хотим, чтобы эта функция выполнялась при нажатии кнопки. В этом случае целевым объектом будет данный контроллер представления.

Использование селекторов

Селектор используется для описания имени функции.

Проще всего сравнить селекторы с записью инструкции на листе бумаги и передачей ее кому-то другому. Вместо того, чтобы напрямую указывать, что делать («пнуть по мячу»), вы пишете «пнуть по мячу» на листе бумаги с мыслью, что кто-то прочтет это и выполнит команду.

Swift не использует селекторы, но Objective-C использует. И поскольку многие фреймворки iOS написаны на Objective-C, и мы используем их вместе со Swift, мы также используем селекторы в Swift.

Начиная со Swift 2.2+, вы можете использовать синтаксис #selector(…):

#selector(functionToExecute(_:))

Селектор — это ссылка на функцию, которую нужно использовать. Перед запуском приложения Swift проверяет, действительно ли существует данный селектор. Если этого не произойдет, вы увидите сообщение об ошибке. Это помогает уменьшить количество ошибок, потому что вы можете отследить их на ранней стадии.

В сигнатуре селектора используется одна или несколько меток аргументов в круглых скобках:

  • Функция fireworks() имеет сигнатуру fireworks (без аргументов, без скобок).
  • Функция fireworks(intensity: Int) имеет сигнатуру fireworks(intensity:) (круглые скобки, метка аргумента, за которой следует двоеточие).
  • Функция fireworks(intensity: Int, size: Int) имеет сигнатуру fireworks(intensity:size:) (круглые скобки, несколько меток с двоеточиями).
  • Если параметр не имеет имени, его метка в вызове функции имеет сигнатуру в виде нижнего подчеркивания, например fireworks(_ intensity: Int, color: UIColor) имеет сигнатуру fireworks(_:color:).

Также мы можем создать расширение для структуры Selector:

extension Selector {
    static let fireworks = #selector(Effects.fireworks)
    static let onButtonTapped = #selector(ViewController.onButtonTapped(_:))
}

Теперь вы можете использовать селектор как константу:

button.addTarget(self, selector: .onButtonTapped, for: .touchUpInside)

Не забудьте добавить @objc атрибут к функции, которую вы хотите использовать с target-action. Это сделает функцию доступной для Objective-C. Это необходимо, потому что UIControl(и target-action) является классом Objective-C.

Target-Action в практической разработке

Target-Action часто используется во фреймворках iOS, в первую очередь в UIKit. Практически каждый компонент пользовательского интерфейса использует целевое действие для реакции на ввод пользователя.

Рассмотрим класс UIButton. Он использует целевое действие, чтобы реагировать на нажатие пользователем кнопки с помощью события .touchUpInside.

Аналогичным элементом пользовательского интерфейса является переключатель UISwitch. Этот класс генерирует событие .valueChanged при нажатии на переключатель. Вы можете отслеживать это событие, используя функцию addTarget(_:action:for:).

Другой класс, использующий механизм целевого действия, — это NotificationCenter. С помощью NotificationCenter вы можете транслировать уведомления. Данный механизм идеально подходит для трансляции событий между одним или несколькими несвязанными компонентами вашего приложения.

NotificationCenter.default.addObserver(self, selector: #selector(onDidReceiveData(_:)), name: .didReceiveData, object: nil)

Другой компонент, который использует target-action, это таймеры:

Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(fire), userInfo: nil, repeats: true)
Читайте также:
Добавить комментарий

Ваш адрес email не будет опубликован.