새소식

인기 검색어

iOS/iOS

[iOS] UIResponder, Responder Chain, First Responder

  • -

UIResponder

An abstract interface for responding to and handling events.

이벤트의 응답 및 처리를 위한 추상 인터페이스

 

 

Responder objects(UIResponder의 인스턴스들)들은 UIKit 앱 이벤트 처리를 위한 backbone을 구성

UIApplication, UIViewController, 및 모든 UIView(UIWindow포함)와 같은 많은 핵심객체들이 Responder

이벤트가 발생하면 UIKit이 이 이벤트를 처리할 수 있도록 앱의 Responder objects에 전달

 

이벤트에는 여러종류가 있음

touch events, motion events, remote-control events, press events 가 포함

예를 들어 touch events를 처리하고 싶으면 리스폰더는 아래 네가지 함수를 구현하여야 함

이처럼 처리하고 싶은 이벤트가 있다면 해당 이벤트에 맞는 함수를 구현하면 됨

UIKit Responder 이벤트 처리 이외에도 처리되지 않은 이벤트를 앱의 다른 부분으로 전달하는 역할도 함

이벤트가 발생했을 때 주어진 Responder가 이벤트를 처리하지 않으면 Responder chain을 통해 해당 이벤트를 다음 이벤트로 전달

UIKit은 미리 정의된 규칙에 따라 Responder Chain을 동적으로 관리하여 이벤트를 수신한 뒤 다음 이벤트를 전달할 객체를 선택

 

예를 들어 view는 이벤트가 발생하면 superview로 이벤트를 전달하고, 계층의 root view는 이벤트를 해당 뷰의 view controller로 전달

리스폰더는 UIEvent  객체를 처리하지만 input view를 통해서 custom input을 받는 것도 가능

키보드가 가장 대표적인 custom input

사용자가  UITextField 와 UITextView를 탭하면 해당 뷰는 first responder가 되어 input view 즉 키보드를 표시

이처럼 개발자는 custom inputView를 만들어 다른 responder가 활성화 되었을 때 해당 custom View를 보여줄 수 있음

custom input view를 리스폰더와 연결하려면 해당 view를 respodner의 inputView에 할당

 

UIResponder Chain

 

이벤트를 입력 받았을 때 이 이벤트를 처리할 Responder object를 찾는 순서

 

  • UIVIew objects
    • 이벤트를 처음 받은 UIView 객체들이 이벤트를 처리하려고 시도
    • 이벤트를 처리하지 못했을 때
      • 다음 responder는 해당 view의 superview
      • 즉 처리하지 못한 이벤트를 superview로 전달
      • 만약 해당 view가 viewController의 root view라면 다음 responder는 viewController
  • UIViewController objects
    • viewController의 view로 부터 전달받은 이벤트를 처리하려고 시도
    • 이벤트를 처리하지 못했을 떄
      • 현재 viewController가 window의 root view라면 다음 responder는 window object
      • 만약 viewController가 다른 viewController에 의해 present된 것이라면 다음 responder는 present한 viewController
  • UIWindow objects
    • viewController에서 전달받은 이벤트를 처리하려고 시도
    • 이벤트를 처리하지 못했을 때
      • window의 다음 responder는 UIApplication object
  • UIApplication object
    • window로 전달받은 이벤트를 처리하려고 시도
    • 이벤트를 처리하지 못했을 때
      • 다음 responder는 app delegate지만 app delegate는 UIResponder의 instance여야 하고 UIView, UIViewController, 그리고 app object 자체가 아니여야 함(UIApplication을 말하는 듯)

 

단 가속도계, 자이로스코프 및 자력계와 관련된 motion 이벤트들은 responder chain을 따르지 않음

대신 core motion은 이런 이벤트들은 지정된 객체로 직접 전달 함

자세한 내용은 Core Motion Framework 참조

 

First Responder

 

UIKit은 발생한 event type(UIEvent.EventType)을 기준으로 First Responder를 결정

 

터치 이벤트를 예시로 first Responder를 찾는 방법

UIKit은 view-based hit-testing을 사용, 터치 이벤트가 어디서 발생했는지를 결정

구체적으로 UIKit은 touch location을 view hierarchy내의 있는 view objects들의 bounds와 비교

UIView의 hitTest 메소드는 view hierarchy을 순회하면서 터치가 발생한 위치(touch location)를 포함하는

가장 최하단의 subView를 찾고 그것을 touch event의 first Responder로 지정한다.

만약 touch location이 view의 bounds를 벗어났다면, 즉 터치가 view의 영역 바깥에서 일어났다면

hitTest는 해당 view와 view의 subView들을 무시한다.

결과적으로 view의 clipsToBounds 프로퍼티가 true일 경우엔 subViews의 영역 밖에서 터치가 일어나도 리턴되지 않는다.

 

hitTest의 자세한 것은 hitTest 포스팅 참조

https://junbok97.tistory.com/363

 

HitTest

Responder Chain에서 나온 hitTest터치 이벤트에 반응한 View가 어떤것인지 알아보기 위해 필요한 것이 hitTestHitTest터치 이벤트가 발생한 포인트에 있는 view중 view hierarchy에서 가장 멀리 있는 하위 view즉

junbok97.tistory.com

 

 

Example

각 View, VC, AppDelegate에 아래 함수 추가

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print(#function, String(describing: type(of: self)))
        super.touchesBegan(touches, with: event)
    }

 

 

View -> VC rootView이기 때문에 VC로 이벤트 전달 VC1 -> 상위 VC인 NaviVC로 전달 -> AppDelegate로 전달

 

VC1에서 VC2를 push 후 A 터치

A -> VC2의 root view View2 -> VC2 -> NaviVC -> AppDelegate

 

 

 

Navi없이 VC3를 VC1에서 present 후 C 터치

C -> VC3의 root view View3 -> VC3 -> VC1 -> AppDelegate

 

 

 

코드에서 super.touchesBegan(touches, with: event) 를 호출하였기에 event가 최상위 까지 전달

event를 처리하고 싶은곳에서 override후 super를 호출 하지 않으면 이벤트를 상위 객체로 전달하지 않음

 

 

Responder Chain이 끊기는 경우

  • UIScrolView를 상속 받은 뷰들
    • UITableView, UIColectionView
  • Touch Event를 무시하는 경우 (disable isUserInteractionEnabled)
  • 뷰가 안 보이는 경우
    • clipToBounds
    • hidden
    • alpha값 0.1이하 👉Button의 경우 0.05보다 작으면 안 눌림

 

https://github.com/junbok97/iOS-Study/tree/main/%EB%B8%94%EB%A1%9C%EA%B7%B8/UIResponder

 

iOS-Study/블로그/UIResponder at main · junbok97/iOS-Study

Contribute to junbok97/iOS-Study development by creating an account on GitHub.

github.com

 

참고

UIResponder | Apple Developer Documentation

 

UIResponder | Apple Developer Documentation

An abstract interface for responding to and handling events.

developer.apple.com

 

Using responders and the responder chain to handle events | Apple Developer Documentation

 

Using responders and the responder chain to handle events | Apple Developer Documentation

Learn how to handle events that propagate through your app.

developer.apple.com

 

UIEvent.EventType | Apple Developer Documentation

 

UIEvent.EventType | Apple Developer Documentation

Constants that specify the general type of an event.

developer.apple.com

 

[UIKit] UIResponder (feat. Responder, Responder Chain, FirstResponder)

 

[UIKit] UIResponder (feat. Responder, Responder Chain, FirstResponder)

오늘부터 미라클 모닝 시간에 1일 1유아이킷 포스팅을 해보려고한다. 구현위주의 공부를 하다보니, 기초지식이 너무 부족하다고 느껴졌고, UIKit의 구조를 정확하게 파악하고 싶어서 시작! 🔵 UIR

didu-story.tistory.com

 

iOS ) UIResponder

 

iOS ) UIResponder

안녕하세요 :) Zedd입니다.오늘은 UIResponder를 공부해보려고 해요. UIResponder 리스폰더 객체(Responder objects), 즉 UIResponder의 인스턴스는 UIKit 앱 이벤트 처리 백본(backbone)을 구성합니다.많은 핵심 객체

zeddios.tistory.com

 

UIKit 계층구조와 UIView

 

UIKit 계층구조와 UIView

우리가 끌어다쓰던 UI요소들이 사실은 UIKit에 클래스로 구현이 되어있는 것들이다. 하나 하나 살펴보자.

medium.com

 

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.