리스폰더 체인
은 리스폰더 오브젝트
들이 동적으로 이벤트를 전달하는 체인이다.
app은 리스폰더 오브젝트
를 사용하여 이벤트를 처리한다.
🤔
리스폰더 오브젝트
는 뭐지? UIReponder 클래스의 인스턴스를 가리킨다.
대표적으로 UIView(UIView의 서브클래스), UIViewController, UIApplication
리스폰더는 이벤트를 받았다면 반드시 해당 리스폰더는 이벤트를 처리하거나, 다음 리스폰더 오브젝트로 넘겨주어야한다.
만약 다음 리스폰더 오브젝트도 처리할 수 없다면? 그 다음 리스폰더 오브젝트에게 넘긴다. 그래서 리스폰더 체인이다! 아래 그림처럼!
만약 app이 이벤트가 생기면 UIKit는 이벤트를 처리하기 위한 가장 적합한 리스폰더 오브젝트를 찾고, 해당 오브젝트에 이벤트를 전달한다.
❗️여기서 이벤트를 전달받은 리스폰더 오브젝트를
First Responder
라고 한다.
이벤트를 처리할 수 없는 리스폰더라면 다음 리스폰더에게 전달한다고 했는데 다음 리스폰더가 뭘까...?
❗️해당 리스폰더의
superView
가다음 리스폰더
다!
위 그림 예시에서 보면 UILabel은 최하위 UIReponder 클래스의 인스턴스이다.
이러한 상황에서 UILabel이 이벤트를 처리할 수 없다면 UILabel의 superView인 UIView에게 이벤트를 전달한다. 이러한 방법으로 이벤트를 처리하기에 적합한 리스폰더를 찾을 때까지 반복한다.
결국 두번째 청록색 UIView까지 왔다면 UIView를 소유한 UIViewController에 전달되고, UIViewController는 다시 UIWindow에게 전달한다.
이후 UIWindow에서도 이벤트를 처리할 수 없다면 UIApplication에게 전달된다.
이루 UIAppplicationDelegate에 전달될 수도 있다.
UIKit이 First Responder를 결정하는 기준은 무엇일까?
❗️발생한
이벤트의 타입
에 따라 결정한다!
컨트롤은 UIControl을 상속받은 클래스의 오브젝트들을 뜻한다. (컨트롤은 target-action mechanism으로 이벤트를 처리한다.) 그래서 컨트롤은 액션 메시지를 통해 자신의 타겟 오브젝트와 소통한다.
액션 메시지는 이벤트와는 다른 개념이다. 하지만 이벤트와 마찬가지로 리스폰더 체인을 이용하여 액션 메서드를 구현한 오브젝트를 찾아다닌다. 컨트롤의 타겟 오브젝트가 설정되어 있지 않을 경우, UIKit은 액션 메서드를 구현한 오브젝트를 찾을 때까지 리스폰더 체인을 통해 돌아다닌다.
만약 View 앞에 Gestsure recognizer가 존재한다면, Gestsure recognizer가 먼저 이벤트를 낚아채고 처리를 시도한다. 실패하면? 그냥 무시하고 리스폰더 체인에 따라 이벤트가 전달되고, 액션 메서드가 구현된 곳을 찾을 때까지 찾아다닌다.
기기들은 어떻게 내가 터치한 위치가(이벤트가 발생한 위치가) 어딘지 알까?
바로 UIKit은 view-based hit-testing
을 사용하여 더치 이벤트가 어디에서 발생했는지 결정한다.
UIKit은 터치 위치를 뷰 계층 구조의 뷰 객체 경계와 비교한다. UIView의 hitTest(_:with:)
메서드는 뷰 계층을 통과하여 지정된 터치를 포함하는 최하위 뷰를 찾는다.(지정된 터치 위치를 포함하는 최하위 뷰) 이 하위 뷰는 터치 이벤트에 대한 first responde
가 된다.
만약 터치 이벤트가 발생한 위치가 뷰의 bounds 의 밖에 있다면,
hitTest(:with:)
는 해당 뷰와 서브뷰를 모두 무시한다.
참고: [iOS] 리스폰더 체인 (Responder Chain) 이란? (feat. UIResponder, First Responder, UIEvent)