야곰 캠프 활동학습 중 나온 주제이다. 개발자 문서에서 빈번하게 등장하는 Responder Chain
개념에 대해서 알아보자!
Responder는 이벤트를 핸들링하고 이벤트에 반응할 수 있는 객체이다. 아래를 보면 UIView
가 UIResponder
를 상속하고 있는 것을 볼 수 있다. UIApplication
, UIViewController
, UIWindow
를 포함한 많은 중요 객체 또한 responder이다
이벤트 종류로는 터치, 모션, 원격 조정(ex: 에어팟을 통한 원격조정) 이벤트 등이 있다. UIResponder
메서드에 위 이벤트 종류별 대응되는 메서드들이 있다. 해당 메서드를 오버라이드해서 구현하면 된다. 터치 이벤트를 핸들링하기 위해서는 touchesBegan(_: with:)
와 같은 메서드를 구현해야된다.
UIResponder
의 메서드는 아니지만 UIView
의 메서드인 hitTest(_:with:)
의 경우 touchesBegan(_: with:)
와 같이 해당 View가 터치되었을 경우 호출된다
touchesBegan의 경우는 UIResponder의 메서드라는 점, hitTest는 UIView에서 정의된 메서드라는 점이 차이점이지만, 또 다른 차이점이 있다. 다른 차이점은 일단은 남겨두고 밑에서 알아보자!
이벤트 핸들링 말고도, UIKit responder들은 처리되지 않은 이벤트를 다른 항목으로 미루는 일도 담당한다. Responder chain은 responder 객체들이 이벤트나 액션 메시지를 핸들링할 책임을 앱의 다른 객체들에게 전송할 수 있도록 해준다. 특정 정해진 responder가 이벤트를 핸들링하지 않을 경우, 해당 responder는 그 이벤트를 responder chain의 다음 객체에게로 포워딩한다. 메시지는 처리될 때까지 계속 chain의 상위 객체들로 이동한다. 마지막까지 처리되지 않을 경우, 앱이 해당 메시지를 버린다.
위 그림처럼 responder chain path는 일반적으로 정해져 있다. 뷰(first responder)를 시작으로 ViewController
, UIWindow
, UIApplication
까지 올라간다.
위 그림을 직접 눈으로 확인해보기 위해서, Xcode에서 구현해봤다.
빨간색으로 표시되어 있는 RedView를 터치했을 경우, 해당 View 가 FirstResponder
이지만 이벤트에 대한 핸들링을 해주지 못하므로 상위 View의 touches began
메시지가 출력되는 것을 볼 수 있다
그렇다면 FirstResponder
인 요소가 이벤트에 대한 핸들링을 해준다면??? 어떻게 될까?? Responder Chain
에 따라 상위로 올라가지 않겠지??
실제로 위 사진의 TextField
를 터치 했을 경우 시스템 키보드가 올라오면서 이벤트 핸들링이 이뤄지기 때문에 Responder Chain
에 따라 상위로 올라가지 않는다~
오? 근데 보면 hitTest
는 꾸준히 출력이 되네??~
이를 통해서 hitTest
는 First Responder
에서 이벤트 핸들링이 이뤄진다고 해도 무조건 실행되어야 하는 로직이 있을 경우 해당 메서드에서 작성해주면 될 것이라는 예측?, 기대?를 해보면 될 것 같다!
Gesture Recognizer
Tap Gesture Recognizer를 위 코드에서 실행시켜보면 알겠지만, Gesture Recognizer가 올려져 있는 View가 First Responder가 될 가능성?이 없을 경우에 실행되지 않는 것을 알 수 있다. Gesture Recognizer 는 Responder Chain과는 별개이며, UIResponder 메서드가 실행된 이후에 제일 마지막에 호출되는 것도 기억하자!
터치가 됐을 때 View랑 Tap gesture recognizer중에 어떤 친구가 먼저 반응할까?
hitTest → touches → Tap Gesture Recognizer
Responder Chain
의 super → subclass 순서로 반응함!