UIResponder
UIResponder의 정의는 이벤트에 응답하고 처리하기 위한 추상적인 인터페이스 라고 합니다.
이 글은 공식문서 기반으로 작성하였습니다.
https://developer.apple.com/documentation/uikit/uiresponder
UIResponder | Apple Developer Documentation
An abstract interface for responding to and handling events.
developer.apple.com
Responder Object (= UIResponder의 인스턴스)는 UIKit 앱의 이벤트 처리 백본(backbone)을 구성합니다.
많은 주요 Object도 Responder이며, 여기에는 UIApplication 객체, UIViewController 객체 및 모든 UIView 객체(UIWindow 포함)가 포함됩니다. 이벤트가 발생하면 UIKit은 앱의 Responder 객체에 이벤트를 전송하여 처리합니다.
-> 실제로 UIResponder 클래스는 UIView, UIViewController, UIWindow 등 iOS 앱의 기본 구성 요소들이 상속받는 클래스이기도 합니다.
-> Responder 객체에 이벤트를 전송하여 처리한다 라는 말은
"굳이 이벤트를 직접 만들지 않아도, 우리가 쓰는 대부분의 객체들이 자동으로 이벤트 처리 능력을 갖추고 있다" 정도로 해석하면 됩니다.
즉 사용자가 화면을 터치하거나 어떤 입력을 하면, UIKit이 자동으로 적절한 Responder(예: UIButton이나 UIViewController)에게 그 이벤트를 전달해서 처리하게 합니다.
흠 .. 좀 더 읽어 봅시다.
이벤트에는 터치 이벤트, 모션 이벤트, 리모컨 이벤트, 프레스 이벤트 등 여러 종류가 있습니다. 특정 유형의 이벤트를 처리하려면 Responder가 해당 메서드를 재정의해야 합니다. 예를 들어 터치 이벤트를 처리하기 위해 Responder는 touchesBegan(:with:), touchesMoved(:with:), touchesEnded(:with:), touchesCancelled(:with:) 메서드를 구현합니다. 터치의 경우 Responder는 UIKit에서 제공하는 이벤트 정보를 사용하여 해당 터치의 변경 사항을 추적하고 앱의 인터페이스를 적절하게 업데이트합니다.
공식 문서에 나와 있는 대표적인 메서드는 다음과 같습니다:
1. touchesBegan(_:with:): 터치가 시작될 때 호출
2. touchesMoved(_:with:): 터치가 이동할 때 호출
3. touchesEnded(_:with:): 터치가 끝났을 때 호출
4. touchesCancelled(_:with:): 시스템에 의해 터치가 취소됐을 때 호출
이 메서드들은 override(재정의)를 통해 필요한 동작을 구현할 수 있으며, 해당 이벤트를 처리하지 않을 경우 다음 responder에게 넘길 수 있습니다.
다음 responder에게 넘긴 다는 게 무슨 말일까요?
실제로 UIResoponder는 다음 과 같은 속성들을 가지고 있는 것을 알 수 있는데
next 저장 속성을 통해 다음 responder를 return 해주는 것을 볼 수 있네요!
이어서 Responder Chain의 동작 방식에 대해 더 자세히 살펴보겠습니다.
UIKit Responder는 이벤트를 처리하는 것 외에도 처리되지 않은 이벤트를 앱의 다른 부분으로 전달하는 것도 관리합니다. 지정된 Responder가 이벤트를 처리하지 않으면 해당 이벤트를 Responder Chain의 다음 객체로 전달합니다. UIKit은 미리 정의된 규칙을 사용하여 이벤트를 수신할 다음 객체를 결정함으로써 Responder 체인을 동적으로 관리합니다. 예를 들어 View는 이벤트를 상위 View로 전달하고 계층 구조의 루트 View는 이벤트를 해당 ViewController로 전달합니다.
이것을 알려면 Responder Chain을 공부해야 합니다.
다음으로 Responder Chain을 통해 이벤트를 처리하는 방법에 대해 알아보겠습니다.
Using responders and the responder chain to handle events | Apple Developer Documentation
Learn how to handle events that propagate through your app.
developer.apple.com
앱은 Responder 객체를 통해 이벤트를 수신하고 처리합니다.
Responder 객체는 UIResponder 클래스의 인스턴스이며, 일반적으로 UIView, UIViewController, UIApplication과 같은 하위 클래스들이 이에 해당합니다.
Responder는 원시 이벤트 데이터를 수신하고,
그 이벤트를 직접 처리하거나, 처리하지 않을 경우 다른 Responder 객체로 전달해야 합니다.
이벤트가 발생하면 UIKit은 해당 이벤트를 자동으로 가장 적절한 객체인 첫 번째 Responder(First Responder)에게 전달합니다.
처리되지 않은 이벤트는 앱 내의 Responder 객체들이 동적으로 구성한 Responder Chain을 따라,
한 Responder에서 다음 Responder로 순차적으로 전달됩니다.
아래 그림은 UILabel, UITextField, UIButton, 두 개의 backgroundView로 구성된 인터페이스를 가진 앱에서
어떻게 Responder들이 구성되어 있는지를 보여줍니다.
또한 이 다이어그램은 이벤트가 Responder Chain을 따라 이동하는 과정을 시각적으로 설명합니다.
예를 들어 UITextField가 이벤트를 처리하지 못할 경우, UIKit은 해당 이벤트를 UITextField의 부모인 UIView 객체로 전달합니다.
그 이후에는 해당 뷰 계층의 최상단인 루트 뷰(rootView)로 이벤트가 올라가고,
루트 뷰(rootView)에서도 이벤트를 처리하지 않으면, UIKit은 이벤트를 해당 뷰를 관리하는 UIViewController로 넘깁니다.
이후에도 이벤트가 처리되지 않으면, 이벤트는 UIWindow로 전달되며,
UIWindow에서도 처리할 수 없다면 UIKit은 이벤트를 UIApplication 객체로 넘깁니다.
만약 아직까지 이벤트가 처리되지 않고, UIApplication 역시 처리할 수 없다면,
UIKit은 UIResponder를 상속하는 객체 중 아직 Responder Chain에 참여하지 않은 인스턴스,
예를 들어 AppDelegate 같은 객체에게 이벤트를 넘기기도 합니다.
아래 Chain 모양처럼 말이죠!
UITextField
↓
superview (UIView)
↓
RootView (뷰 계층 최상단)
↓
해당 View를 관리하는 UIViewController
↓
UIWindow
↓
UIApplication
↓
(필요 시) AppDelegate <UIApplicationDelegate>
즉 이벤트를 현재 객체(UIView)가 처리하지 않으면, UIKit이 이벤트를 처리할 수 있는 다른 객체(UIViewController)에게 전달한다는 의미예요.
First Responder 지정 기준
UIKit은 이벤트 유형에 따라 First Responder를 지정합니다.
이벤트 유형 | First Responder 대상 |
터치 이벤트 (Touch) | 터치가 발생한 UIView |
포커스/버튼 이벤트 (Press) | 포커스를 갖고 있는 객체 |
흔들기 이벤트 (Shake) | 개발자 또는 UIKit이 지정한 객체 |
리모컨 이벤트 (Remote) | 개발자 또는 UIKit이 지정한 객체 |
편집 메뉴 메시지 | 개발자 또는 UIKit이 지정한 객체 |
“지정한 객체”라는 말은 becomeFirstResponder()를 호출하여 직접 지정했거나, UIKit이 컨텍스트에 따라 자동 지정한 경우를 말합니다.
예를 들어, UITextField는 자동으로 First Responder가 되며 키보드가 올라옵니다.
🔸 참고: 가속도계, 자이로, 자기장 센서 이벤트는 Responder Chain을 따르지 않고 Core Motion이 직접 처리합니다.
Action 메시지와 Responder Chain
UIKit의 UIButton 같은 Control들은 target 객체에게 Action 메시지를 직접 전달합니다.
하지만 타겟이 nil인 경우, Responder Chain을 따라 메서드를 찾습니다.
예를 들어 cut(_:), copy(_:), paste(_:). 같은 편집 메뉴는 이 방식으로 작동합니다.
Gesture Recognizer와 Responder
UIGestureRecognizer는 터치나 프레스 이벤트를 View보다 먼저 받습니다.
만약 제스처 인식에 실패하면, UIKit은 해당 이벤트를 View에 전달하고
View도 처리하지 않으면 Responder Chain을 따라 이벤트가 전달됩니다
터치 이벤트의 대상 찾기 (Hit-Testing)
UIKit은 터치 이벤트 발생 위치를 기준으로 가장 적합한 UIView를 찾아 이벤트를 전달합니다. (추후 공부 할 내용..)
이를 위해 UIView의 hitTest(_:with:) 메서드를 사용합니다.
- 이 메서드는 가장 깊은 서브뷰까지 탐색하며 (DFS)
- 해당 뷰가 bounds 밖에 있거나 clipsToBounds = true인 경우에는 무시됩니다.
📌 터치 위치가 밖으로 벗어나도, 최초에 매핑된 UITouch.view는 바뀌지 않음에 주의하세요!
마지막으로 Responder Chain을 변경할 수도 있습니다.
Responder Chain 변경하기
기본적으로 UIKit은 Responder Chain을 자동으로 구성하지만,
UIResponder의 next 프로퍼티를 override 하여 수동으로 연결 구조를 바꿀 수도 있습니다.
클래스 | next의 기본 동작 |
UIView | 루트 뷰면 → UIViewController, 아니면 → superview |
UIViewController | 루트 뷰면 → UIWindow, 아니면 → presenting VC |
UIWindow | → UIApplication |
UIApplication | → AppDelegate (단, UIResponder인 경우만) |
마무리
이번 문서를 정리하면서, UIResponder는 단순히 이벤트를 받는 객체가 아니라, 이벤트를 직접 처리하거나 다음 객체로 전달하는 역할까지 맡고 있는 핵심 인터페이스라는 점을 명확히 이해하게 되었습니다.
그리고 이 이벤트가 전달되는 경로는 Responder Chain이라고 불리는 구조를 통해 이루어지며, UIKit은 이벤트 유형에 따라 적절한 First Responder를 자동으로 지정해 주는 덕분에, 개발자는 대부분의 경우 복잡한 이벤트 전달 과정을 의식하지 않고도 개발할 수 있습니다.
하지만 필요한 경우에는 becomeFirstResponder() 호출이나 next 프로퍼티 오버라이드, 또는 Gesture Recognizer, Hit-Testing 같은 다양한 방식으로 이벤트 흐름을 커스터마이징 할 수 있는 유연성 또한 함께 제공된다는 점도 배웠습니다.
학습 내용 중 잘못된 부분이나 보완이 필요한 점이 있다면 댓글로 남겨주시면 감사히 반영하겠습니다.
- 참고자료
Using responders and the responder chain to handle events | Apple Developer Documentation
Learn how to handle events that propagate through your app.
developer.apple.com
https://developer.apple.com/documentation/uikit/uiresponder
UIResponder | Apple Developer Documentation
An abstract interface for responding to and handling events.
developer.apple.com
Xcode 16.0
iOS 18.3
MacOS Sequoia 15.3.1
환경에서 작성 한 글입니다.
감사합니다. 🤗
'iOS' 카테고리의 다른 글
[SwiftUI] List Row separator 왼쪽 패딩 지우는 방법 (0) | 2025.04.24 |
---|---|
[SwiftUI] @ObservedObject vs @StateObject (0) | 2025.02.10 |
[iOS] SwiftUI Tutorials (6) | 2024.11.11 |
[iOS] App Life Cycle (앱의 생명 주기) (0) | 2024.11.09 |
[iOS] 앱스토어 긴급, 빠른 심사 하는 방법 (AppStore Quick Review) (1) | 2024.10.21 |