[ios] Responder Chain and Touch Event
Overview
앱은 응답자 객체를 이용해 이벤트를 받고 처리합니다. 응답자 객체는 UIResponder
클래스의 객체로 서브클래스로는 UIView
, UIViewController
, UIApplication
등이 있습니다. 응답자 객체는 이벤트 데이터를 받고 반드시 이를 직접 처리하거나 다른 응답자 객체에게 전달해야 합니다. 이벤트가 발생하게 되면 앱은 해당 이벤트를 처리할 수 있는 가장 적절한 응답자 객체에게 이벤트 데이터를 전달하고 이를 first responder라 합니다.
first responder가 이벤트를 반드시 처리하라는 법은 없죠! 이렇게 처리되지 않은 이벤트들은 first responder로부터 시작하는 Repsonder Chain을 따라 이벤트를 처리하는 객체를 찾아 거슬러 올라갑니다. 이런 Responder Chain은 앱의 구조에 따라 동적으로 형성됩니다.
다음의 다이어그램을 예를 들어 살펴보도록 하겠습니다.
만일 UITextField
에 이벤트가 들어왔다고 가정했을 때 UITextField
가 해당 이벤트를 처리하지 않는다면 그 이벤트 객체는 부모 뷰인 UIView
에게 넘어가고 역시 처리되지 않으면 UIViewController
, UIWindow
순으로 거슬러 올라가며 자신을 처리해줄 응답자 객체를 찾습니다. 하지만 끝까지 처리되지 않은 이벤트들은 버려지게 됩니다.
그렇다면 이러한 이벤트에는 어떤 것들이 있을까요? 이벤트 타입과 이벤트 타입 별 first responder를 살펴보겠습니다.
Event Type
Event Type | First Responder |
---|---|
Touch Events | Touch가 발생한 뷰 |
Press Events | Press가 발생한 뷰 |
Shake-motion Events | 사용자 혹은 UIKit이 지정한 객체 |
Remote-control Events | 사용자 혹은 UIKit이 지정한 객체 |
Editing Menu Messages | 사용자 혹은 UIKit이 지정한 객체 |
Editing Menu는 텍스트를 길게 눌렀을 때 나타나는 편집 메뉴를 말합니다. (Select, Select all, Copy 등등)
여러 이벤트 타입 중 오늘은 터치 이벤트에 집중해서 포스팅해보도록 하겠습니다.
Touch Events
터치 이벤트가 발생하는 순간부터 이벤트가 응답자 객체에게 전달되는 과정을 먼저 살펴보도록 하겠습니다.
Hit Testing
먼저 터치 이벤트가 발생하면 해당 터치가 어느 뷰에서 발생했는지를 아는 것이 중요합니다. 기본적으로 터치가 발생한 뷰가 해당 이벤트에 대한 first responder가 되기 때문에 터치 이벤트 객체를 해당 뷰에 전달해야하기 때문입니다.
iOS에서는 Hit Testing을 통해 터치가 발생한 뷰를 찾아낼 수 있고 해당 뷰에 이벤트 객체를 전달합니다. Hit Testing에 관해서는 제가 작성한 글을 참고해주시기 바랍니다.
이렇게 이벤트가 전달되는 과정을 자세히 살펴보기 위해서는 몇 가지 클래스들에 대해 살펴보아야 합니다.
UIResponder
UIEvent
UITouch
UIResponder
위에서 언급했듯이 이벤트를 처리하는 객체가 바로 UIResponder
를 상속받은 클래스의 객체들입니다. UIView
, UIViewController
그리고 UIWindow
등이 있습니다. 전달되는 이벤트 종류에 따라 해당 클래스들의 UIResponder
메소드들을 재정의해주면 됩니다.
이벤트 타입 별 메소드들이 존재하지만 터치 이벤트를 핸들링하는 메소드들만 간략하게 나열해보겠습니다.
Responding to Touch Events
func touchesBegan(Set<UITouch>, with: UIEvent?)
func touchesMoved(Set<UITouch>, with: UIEvent?)
func touchesEnded(Set<UITouch>, with: UIEvent?)
func touchesCancelled(Set<UITouch>, with: UIEvent?)
func touchesEstimatedPropertiesUpdated(Set<UITouch>
다른 이벤트들에 대한 메소드는 공식 문서를 참고해주세요.
또한 응답자 객체는 이벤트 객체를 다룰 뿐만 아니라 inputView
를 통해 입력 값도 받을 수 있습니다. 대표적인 예가 바로 UITextField
로 UITextField
를 터치하면 시스템 키보드가 올라오는 것을 확인하실 수 있습니다.
UIEvent
이벤트 객체는 타입별로 이벤트가 발생했을 때 생성되고 응답자 객체에 전달됩니다. 이벤트 객체에서 중요한 것은 같은 이벤트에 대한 객체는 재사용된다는 것입니다. 즉 어플리케이션이 실행되고 터치 이벤트가 처음으로 발생되면 터치 이벤트를 담는 이벤트 객체가 생성되고 이 객체는 다음 터치 이벤트에서도 재사용됩니다. 이는 연속적이지 않아도 해당됩니다.
저는 객체가 재사용되는지를 확인하기 위해 객체의 고유값을 확인할 수 있는 ObjectIdentifier
를 사용하여 비교하였습니다. ObjectIdentifier
의 예시는 다음과 같습니다.