[Apple] Using Responders and the Responder Chain to Handle Events

J.Noma·2021년 12월 26일
0

iOS : 이벤트 처리

목록 보기
3/8

Apple문서: Using Responders and the Responder Chain to Handle Events


요약

  • 유저가 발생시킨 이벤트들이 App에서 어떻게 전파되어 처리되는지에 대해 다룹니다

🦊 Overview

Responder Object
App은 responder objects를 통해 이벤트를 받고 처리합니다. responder objects는 UIResponder class의 인스턴스로 UIView, UIViewController, UIApplication의 부모 class이기도 합니다.

다른 Responder에게 event를 넘길 수 있다
responder는 raw event data를 받으면 직접 처리하거나 다른 responder에게 넘겨야 합니다. App이 event를 받으면, UIKit이 자동으로 이 event를 가장 적절한 first responder를 선정하여 전달합니다.

Responder Chain을 따라 event를 넘긴다
처리되지 않은 event들은 active한 responder chain이란 곳 내에서 한 responder에서 다른 responder로 전달됩니다. responder chain은 responder object들의 동적인 설정입니다.(실시간으로 바뀔 수 있다는 뜻인듯?)

아래 그림은 label, text field, button, 2개의 background view를 가지는 App에서의 responder들을 표현한 것입니다. 또한, event들이 어떻게 (responder chaing을 따라) 한 responder에서 다음 responder로 옮겨가는지를 보여줍니다

상황 예시
만약 text field가 event를 처리하지 않는다면, UIKit은 이 event를 부모 UIView로 보낸 후 window의 root view로 보냅니다. 이후 root view에서 window로 event를 보내기 전에, 자신이 소유한 ViewController로 우회했다가 전달됩니다.

만약 window마저 event를 처리할 수 없다면, UIKit은 event를 UIApplication 객체로 보냅니다. 그리고 UIApplicationDelegate 객체가 UIResponder의 인스턴스이고 아직 responder chain의 일부가 아니라면 UIApplicationDelegate으로 보냅니다.



🐹 First Responder 결정

✔️ Event 별 First Responder

UIKit은 event의 유형에 따라 first responder 객체를 결정합니다

✅ NOTE
가속도, 평형상태, 자력계와 관련한 모션 event는 responder chain을 따르지 않습니다. 대신, Core Motion Framework가 이 event들을 직접적으로 특정 객체들에게 전달합니다

✔️ Control 요소의 First Responder

(버튼, 슬라이더 등과 같은) Control 요소들은 action 메시지를 사용하여 연관된 target 객체와 직접적으로 의사소통합니다. 유저가 Control 요소와 상호작용할 때, Control은 target 객체에게 action 메시지를 보냅니다.

action 메시지가 event는 아니지만, responder chain을 사용할 수 있습니다. 만약 target 객체가 nil이라면, UIKit은 target 객체에서 시작하여 responder chain을 따라 적절한 action 메서드를 구현한 객체를 찾아다닙니다. 예로, 메뉴를 수정하는 UIKit 요소는 cut()/copy()/paste()와 같은 메서드를 구현한 responder 객체를 찾아 다닙니다

✔️ Gesture의 First Responder

view에 있는 Gesture recognizer는 view보다도 먼저 터치와 누르는 event를 받습니다. 만약 gesture recognizer가 일련의 터치들을 인식하는데 실패한다면, UIKit은 이 터치들을 view로 보냅니다. 만약 view마저도 터치들을 처리하지 않는다면, responder chain으로 보내집니다. 이에 대한 정보가 더 필요하다면 Handling UIKit Gestures 참고



🐱 터치 event에 대한 Responder 결정

위에 있는 표에서 살펴봤듯이, 터치 event의 first responder는 'The view in which the touch occurred' 라고 되어 있습니다. 이에 대해 좀 더 자세히 알아봅시다

✔️ 터치 event의 responder는 터치 위치에 기반하여 결정된다

UIKit은 터치 event가 어디에서 발생했는지 알아내기 위해 view에 기반한 hit-testing 방식을 사용합니다. 특히, UIKit은 터치 위치와 화면에 있는 view의 bound들과 비교합니다. UIView의 hitTest(_:with:) 메서드는 view 계층을 뒤져가며 터치에 대해 명시한 subview 중 가장 deep한 것을 찾습니다. 찾아낸 deepest subview가 터치 event의 first responder가 됩니다

✅ NOTE
터치 위치가 view의 bound 밖에 있다면, hitTest() 메서드는 해당 view와 관련된 내부 subview들을 전부 무시합니다. 주의할 점은, view의 clipsToBounds 프로퍼티가 false여서 터치 위치가 상위 view의 밖이지만 subview의 내부인 상황에서도 무시된다는 것입니다. 이런 hit-testing에 대한 자세한 정보는 hitTest(_:with:) 참고

✔️ UITouch 객체

터치가 발생하면 UIKit은 UITouch 객체를 생성하고 view와 연결합니다. 터치 위치 혹은 파라미터가 바뀌면 UIKit이 새로운 정보들을 이 UITouch 객체에 업데이트해줍니다. 변경되지 않는 유일한 프로퍼티는 자신과 연결된 view 프로퍼티입니다 (심지어 터치 위치가 original view를 벗어나더라도 view는 바뀌지 않습니다) 터치가 끝나면 UIKit은 UITouch 객체를 해제합니다



🐶 Responder Chain 변경하기

✔️ 변경 방법

당신은 responder 객체가 가지고 있는 next 프로퍼티를 override함으로써 responder chain을 변경할 수 있습니다. 우리가 override에서 return하도록 구현한 객체가 다음 responder가 됩니다

✔️ 변경 예시: 사실 이미 많은 UIKit class가 Responder Chain을 변경하여 쓰고 있다

많은 UIKit class들은 이미 next를 override한 상태이고 특정 객체를 return하고 있습니다

UIView
-- 기본적으로 view의 next responder는 superview가 됩니다
-- 만약 해당 view가 뷰컨의 root view라면, next responder는 뷰컨이 됩니다.

UIViewController
-- 뷰컨의 view가 window의 root view라면, next는 window가 됩니다
-- 상위 뷰컨이 있다면, next는 상위 뷰컨이 됩니다

UIWindow
-- window의 next는 'UIApplication'입니다

UIApplication
-- 특정 조건 하에서 UIApplication의 next는 UIApplicationDelegate입니다
(특정 조건 : UIApplicationDelegate가 UIResponder의 인스턴스면서 그 자체로 view/뷰컨/App 객체가 아닌 경우)

profile
노션으로 이사갑니다 https://tungsten-run-778.notion.site/Study-Archive-98e51c3793684d428070695d5722d1fe

0개의 댓글