Responder Chain: що це, принцип роботи та ланцюжок відповідачів

Автор: IT Sectr Опубліковано: 2026-07-09 Час читання: 9 хв

Responder Chain — це механізм iOS, який послідовно передає події дотику, натискання клавіш і жестів через ієрархію об'єктів UIResponder, поки один із них не обробить подію. Ланцюжок починається з об'єкта, який виявив подію, і рухається вгору по ієрархії: від view до її superview, потім до view controller, window і, нарешті, до UIApplication. Згідно з Apple Developer Documentation (2026), цей шаблон дозволяє розділити відповідальність за обробку подій між компонентами інтерфейсу, забезпечуючи гнучкість без жорсткого прив'язування до конкретного обробника.

Головне

  • Responder Chain — ієрархічний ланцюжок об'єктів UIResponder для послідовної передачі подій від першого відповідача до UIApplication.
  • Hit-Testing визначає, який об'єкт стане першим у ланцюжку відповідачів, аналізуючи вкладеність view у точці дотику.
  • Кожен UIResponder може обробити подію або передати її далі по ланцюжку через метод next.
  • UIApplication — кінцевий вузол ланцюжка: якщо жоден об'єкт не обробив подію, вона відкидається.
  • Кастомні обробники створюються перевизначенням методів touchesBegan, touchesMoved, touchesEnded у підкласах UIView або UIViewController.

Що таке Responder Chain

Responder Chain — це послідовність об'єктів UIResponder, через які iOS передає вхідні події, такі як дотики, натискання клавіш та дані акселерометра. Кожен об'єкт у цьому ланцюжку має можливість обробити подію або передати її наступному об'єкту-відповідачу через властивість next.

Механізм базується на ієрархії view: коли відбувається дотик, iOS спочатку визначає, яка view була натиснута (через hit-testing), і створює ланцюжок, починаючи з цієї view і піднімаючись до UIApplication. UIApplication є останньою ланкою ланцюжка — якщо подія доходить до нього і не обробляється, вона просто відкидається.

За даними Apple, цей шаблон критично важливий для інкапсуляції логіки обробки подій. Розробник може перевизначити поведінку конкретної view, не зачіпаючи інші елементи ієрархії. Наприклад, UITextField стає first responder при фокусуванні та отримує події клавіатури, не вимагаючи змін у батьківському UIViewController.

Як Responder Chain обробляє події

Обробка подій через Responder Chain відбувається у два етапи: спочатку iOS визначає, яка view отримала подію (hit-testing), потім запускає ланцюжок відповідачів для її обробки. Якщо об'єкт не реалізує відповідний метод, подія передається далі.

Ланцюжок формується динамічно на основі поточного first responder та ієрархії view. Стандартний порядок виглядає так: first responder → його view → superview → UIViewController → root view → UIWindow → UIApplication. Якщо будь-який із цих об'єктів реалізує, наприклад, touchesBegan, подія обробляється на цьому рівні та не передається далі.

swift
import UIKit

class CustomView: UIView {
    override func touchesBegan(
        _ touches: Set<UITouch>,
        with event: UIEvent?
    ) {
        // Дотик оброблено на цьому рівні view
        print("CustomView обробив дотик")
        
        // Переслати подію по ланцюжку
        super.touchesBegan(touches, with: event)
    }
}

Ключова особливість — виклик super.touchesBegan не є обов'язковим. Якщо його не викликати, подія буде оброблена тільки на поточному рівні та не піде далі по Responder Chain. Це дає розробнику повний контроль над тим, які об'єкти беруть участь в обробці.

Передача подій між об'єктами-відповідачами

Коли об'єкт отримує подію, але не обробляє її (не перевизначає метод), iOS автоматично передає подію наступному об'єкту-відповідачу через властивість next. Ця властивість формує однозв'язний список, який і називається Responder Chain.

UIViewController знаходиться між своєю view та UIWindow: якщо view не обробляє подію, контролер отримує шанс це зробити. Це особливо корисно для спільної логіки — наприклад, обробки жесту, який повинен працювати на всій сцені, незалежно від того, яка view під пальцем користувача.

Hit-Testing: від дотику до першого відповідача

Hit-Testing — це процес, за допомогою якого iOS визначає, яка view знаходиться під точкою дотику. Метод hitTest:withEvent: обходить ієрархію view від UIWindow вниз, перевіряючи, яка з дочірніх view містить точку дотику та не прихована.

Алгоритм працює рекурсивно: для кожного рівня iOS перевіряє view у зворотному порядку додавання (спочатку верхні). Якщо view не прихована, не прозора та точка потрапляє в її bounds, для неї запускається hitTest рекурсивно для всіх subviews. Найглибша view, що задовольняє всім умовам, стає hit-test view — першим об'єктом у Responder Chain.

swift
override func hitTest(
    _ point: CGPoint,
    with event: UIEvent?
) -> UIView? {
    if isUserInteractionEnabled &&
        isHidden == false &&
        alpha > 0.01 &&
        point(inside: point, with: event) {
        return super.hitTest(point, with: event)
    }
    return nil
}

Розробники можуть перевизначити hitTest, щоб змінити стандартну поведінку. Наприклад, розширити область дотику для маленької кнопки або перенаправити подію на іншу view, яка фізично не знаходиться під пальцем. Це потужний інструмент для створення кастомних інтерактивних елементів.

Методи UIResponder для ланцюжка відповідачів

UIResponder — базовий клас для всіх об'єктів, які можуть обробляти події в iOS. UIView, UIViewController, UIApplication та UIWindow успадковуються від UIResponder. Клас надає набір методів, які можна перевизначити для обробки різних типів подій.

Основні групи методів включають touchesBegan, touchesMoved, touchesEnded, touchesCancelled для дотиків; pressesBegan, pressesEnded для фізичних кнопок; та motionBegan, motionEnded для подій акселерометра. Кожен метод отримує набір об'єктів UITouch або UIPress та посилання на UIEvent, що містить додаткові метадані про подію.

Метод UIResponderПризначення
touchesBeganВикликається при початку дотику
touchesMovedВикликається при переміщенні пальця
touchesEndedВикликається при відпусканні пальця
touchesCancelledВикликається при перериванні (дзвінок, свайп шторки)
pressesBeganВикликається при натисканні фізичної кнопки

Важливо розуміти, що iOS викликає ці методи тільки для first responder та наступних об'єктів у ланцюжку. Якщо жоден об'єкт не перевизначив метод, подія не генерує помилку — вона просто ігнорується. Для налагодження обробки подій використовуйте Symbolic Breakpoint на UIResponder touchEvent.

Responder Chain та елементи UIKit

Стандартні компоненти UIKit активно використовують Responder Chain для своєї роботи. UITextField стає first responder при отриманні фокусу, що автоматично відкриває клавіатуру. UIButton обробляє дотики через механізм UIControl, який також спирається на responder chain.

UITableView та UICollectionView використовують ланцюжок відповідачів для обробки виділення комірок та жестів прокрутки. Якщо користувач торкається комірки, подія спочатку отримує сама комірка, потім UITableView, і тільки потім UIViewController. UIGestureRecognizer має більш високий пріоритет, ніж touchesBegan — якщо на view додано розпізнавач жестів, він отримає подію першим.

За даними Apple, правильне використання Responder Chain критично важливе для доступності додатку. VoiceOver та інші асистивні технології використовують ланцюжок відповідачів для навігації між елементами інтерфейсу. Якщо ланцюжок розірваний, користувачі з обмеженими можливостями не зможуть взаємодіяти з додатком.

UIMenuController та Responder Chain

UIMenuController для відображення контекстного меню також використовує Responder Chain. Коли користувач викликає меню, система шукає first responder, який реалізує методи canPerformAction та відповідні action-методи. Меню відображається тільки для тих дій, які підтримує поточний responder.

Це дозволяє, наприклад, показати команди Cut, Copy, Paste тільки коли UITextField у фокусі, та приховати їх при роботі з UILabel. Розробник може додати кастомні дії в контекстне меню, реалізувавши їх у підкласі UIResponder та повернувши true з canPerformAction.

Кастомні об'єкти відповідачів в iOS

Створення кастомного об'єкта-відповідача дає розробнику повний контроль над обробкою подій. Для цього потрібно створити підклас UIResponder (або UIView/UIViewController) та перевизначити необхідні методи обробки подій.

Часто кастомні об'єкти-відповідачі використовуються для обробки специфічних жестів, які не покриваються стандартними UIGestureRecognizer. Наприклад, розпізнавання малювання фігур, складних multi-touch комбінацій або пропрієтарних шаблонів введення. Кастомний відповідач може агрегувати події від кількох пальців та приймати рішення на основі їх комбінації.

swift
class DrawingResponder: UIResponder {
    private var activeTouches: [UITouch: CGPoint] = [:]
    
    override func touchesBegan(
        _ touches: Set<UITouch>,
        with event: UIEvent?
    ) {
        for touch in touches {
            activeTouches[touch] = touch.location(in: self)
        }
    }
    
    override func touchesMoved(
        _ touches: Set<UITouch>,
        with event: UIEvent?
    ) {
        for touch in touches {
            let currentPoint = touch.location(in: self)
            activeTouches[touch] = currentPoint
            drawLine(from: activeTouches[touch]!, to: currentPoint)
        }
    }
}

При створенні кастомного відповідача важливо правильно налаштувати ланцюжок next. Якщо ваш об'єкт не є частиною стандартної ієрархії UIKit, необхідно явно вказати, який об'єкт буде його next responder. Це гарантує, що необроблені події продовжать рух по Responder Chain.

Часті запитання

Що таке Responder Chain в iOS?

Responder Chain — це ієрархічний ланцюжок об'єктів UIResponder, через який iOS послідовно передає події дотику, натискань та жестів. Якщо об'єкт не обробляє подію, вона передається наступному об'єкту-відповідачу по ланцюжку до UIApplication.

Як змінити порядок ланцюжка відповідачів?

Змінити порядок можна, перевизначивши властивість next у вашого об'єкта UIResponder. Повернувши інший об'єкт замість стандартного, ви перенаправляєте необроблені події на нього. Це корисно для нестандартних ієрархій, наприклад, коли кастомний контейнер керує кількома дочірніми контролерами.

В чому різниця між hit-test та responder chain?

Hit-Testing визначає, яка view знаходиться під точкою дотику (початковий отримувач), а Responder Chain визначає, як подія передається між об'єктами після hit-test. Hit-test знаходить перший об'єкт, responder chain забезпечує подальшу маршрутизацію, якщо цей об'єкт не обробляє подію.

Як перервати ланцюжок відповідачів?

Щоб перервати ланцюжок, достатньо обробити подію у вашому UIResponder та не викликати super. Наприклад, перевизначивши touchesBegan та не викликаючи super.touchesBegan, ви запобігаєте передачі події далі. Подія буде оброблена на поточному рівні та не досягне наступних ланок ланцюжка.

Чому моя view не отримує дотики?

Найчастіші причини: isUserInteractionEnabled встановлено в false, view прихована (isHidden = true), alpha менше 0.01, або view знаходиться за межами bounds батьківського контейнера. Також перевірте, що на view або її superview немає UIGestureRecognizer, який перехоплює події до touchesBegan.

Підсумки

  • Responder Chain — фундаментальний механізм iOS для маршрутизації вхідних подій через ієрархію UIResponder від first responder до UIApplication.
  • Hit-Testing передує Responder Chain та визначає, яка view отримає подію першою, аналізуючи ієрархію та координати дотику.
  • UIResponder надає методи touchesBegan, touchesMoved, touchesEnded, touchesCancelled, pressesBegan та інші для обробки різних типів подій.
  • Виклик super в методах обробки подій визначає, чи продовжиться передача по ланцюжку або подія буде оброблена на поточному рівні.
  • Компоненти UIKit (UITextField, UIButton, UITableView) активно використовують Responder Chain для стандартної поведінки, включаючи клавіатуру та контекстні меню.
  • Кастомний UIResponder дозволяє реалізувати специфічну обробку подій, не передбачену стандартними UIGestureRecognizer.
  • Правильне налаштування next responder гарантує, що необроблені події дійдуть до потрібного обробника в ієрархії додатку.

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також