스위프트

[Swift] Responder와 FirstResponder에 관한 고찰

아이폰아비치 2021. 9. 3. 11:19

- 필요하게 된 계기 : 회사에서 만든 앱으로 아이패드를 공식지원하자 플로팅 키보드, 하드웨어 키보드 등 다양한 키보드로 입력을 하게되면서 UIResponder의 키보드와 관련된 노티들이 이상하게 튀는 것을 확인했다. 버그를 고치기전에 좀 더 자세히 알아보고 고쳐보고 싶었다.

 

[1] UIResponder

이벤트들을 다루고, 응답하기 위한 추상화된 인터페이스다.

UIResponder의 인스턴스들인 Responder objects은 UIKit 앱의 이벤트 처리 백본을 구성한다.

UIApplication/UIViewController/UIView를 포함해서 많은 핵심 오브젝트들 또한 UIResponder이다.

이벤트가 발생하면, UIKit은 이벤트들을 처리하기위해 나의 앱 Responder Objects들로 이벤트들을 보낸다.

 

Press, Remote-control, Motion, Touch 이벤트들을 포함하여 여러 종류의 이벤트가 있다.

특정 타입의 이벤트들을 처리하기 위해, Responder는 상응하는 메소드들을 반드시 override해야한다.

예를 들어, 터치 이벤트를 처리하기 위해서는 Responder객체는 반드시 아래와 같은 메소드들을 override해야한다.

 

touchesBegan(_:with:)

touchesMoved(_:with:)

touchedEnded(_:with:)

touchedCancelled(_:with:)

 

이런 터치 케이스들에서 Responder 객체는 UIKit에서 제공된 이벤트 정보를 사용하여 터치들에 대한 변화를 추적하고,

앱의 인터페이스를적절히 업데이트한다.

 

이벤트들을 처리하는 것에 추가적으로 UIKit Responder는 또한 자신이 처리할 이벤트가 아닌 경우에는 

앱의 다른 파트로 패스되도록 관리할 수 있다.

만약 특정 이벤트를 처리할 필요가 없는 Responder가 이벤트를 받았을 경우,

해당 객체는 Responder chain에 있는 다음 객체로 보낼 수 있다.

UIKit은 Responder chain을 선정의된 룰을 사용해 다음에 어떤 오브젝트가 이벤트를 받을지 동적으로 관리한다.

뷰같은 경우엔 상위뷰로, 루트 뷰일 경우에는 뷰 컨트롤러로 이런식이다.

 

Responder는 UIEvent를 처리하지만, Input view를 통한 커스텀 인풋 또한 받는다.

시스템 키보드는 Input view의 가장 명확한 예제이다.

유저가 화면에 있는 UITextField 혹은 UITextView를 눌렀을 때,

뷰는 first responder가 되고, 시스템 키보드를 보여주는 Input view를 보여준다.

유사하게 다른 Responder 객체들이 활성화 될 때(firstResponder가 된다는 얘기일까)

커스텀한 인풋 뷰를 만들고 보여줄 수 있다.

커스텀한 인풋 뷰를 UIResponder와 연관짓기 위해서

Responder의 inputview 프로퍼티를 특정 뷰에 생성해라.

 

음..

정리하면 UIResponder는 외부의 이벤트를 받을 수 있도록 정의한 인터페이스이고,

UIApplication, UIViewController, UIView와 같은 객체들이 위 인터페이스를 구현하였으며,

이벤트가 발생하면 UIKit에서 Responder Chain에 따라 적절한 Responder Object가 이벤트를 받을 수 있도록 관리한다.

그럼 이 Responder와 관련되서 쓰는 property들이 있는 데 각각의 의미와 용도를 알아보자.

 

[2] UIResponder의 프로퍼티 및 메소드 분석

이름 공식 설명 용도
next Responder Chain으로 다음 Responder객체를 반환하고 없으면 nil을 반환한다.  
isFirstResponder 현재 Responder Object가 first responder인지 반환한다.  
canBecomeFirstResponder 현재 Responder Object가 first responder가 될 수 있는 지 반환한다.  
becomeFirstResponder() -> Bool UIKit에게 현 Window에서 해당 객체를 first responder가 되도록 요청한다. (무조건 되는게 아님)  
canResignFirstResponder 해당 객체가 first responder 상태의 소유권을 포기할 수 있는 지 반환한다.  
resignFirstResponder() -> Bool 현 Window에서 객체의 상태가 first responder에 대한 소유권을 포기하도록 객체에게 알린다.