Understanding Responders and the Responder Chain
: UIKit은 event가 들어오면 적절한 responder object로 전달한다. responder object는 UIResponder 또는 이를 상속한 subclass들이다. UIView, UIViewController, UIApplication이 이에 해당한다.
제일 처음 event를 전달받는 object를 first-responder라 부른다. first-responder가 event를 처리하지 못하면 event는 responder chain에 의해서 next-responder로 넘어간다. 해당 flow를 그림을 통해 살펴보자.
위 그림에서 사용자가 UITextField를 클릭했다고 가정 시, first-responder인 UITextField가 event를 처리할 것이다. 만약 UITextField가 event를 처리하지 못하면 superview에게 event가 넘어간다. 이렇게 superview를 계속 따라가다보면 root view가 나오는데 root view 마저 event를 처리하지 못하면 UIViewController가 event를 처리하게 된다. 만약 UIViewController도 event를 처리하지 못하면 자신을 present하고 있는 viewController가 있으면 그쪽으로 event를 넘기고 아닐경우 UIWindow가 event를 받고, 역시 처리하지 못할 경우에는 UIApplication이 받아서 event를 UIApplicationDelegate로 넘긴다.
위 로직을 간단히 정리해 보면 다음과 같다.
first-responder -> super view -> UIViewController -> presenting ViewController -> UIWindow -> UIApplication(UIApplicationDelegate)
* 만약, view에 gesture recognizer가 설정되어 있으면 touch event가 무시될 수 있다. 예를 들어 view에 tap gesture recognizer가 설정되어 있고, UIGestureRecognizer의 delaysTouchesBegan이 YES로 설정되어 있으면 해당 view를 tap해도 tap gesture action만 불리고 touchesBegan:withEvent: 메서드를 불리지 않는다.
이러한 제어들은 UIGestureRecognizer의 delaysTouchesBegan, delaysTouchesEnded, cancelsTouchesInView를 통해 할 수 있다.
Determining Which Responder Contained a Touch Event
: UIKit은 어느 view에서 touch가 일어났는지 판별하기 위해서 UIView의 hitTest:withEvent: method를 사용한다. hitTest:withEvent: 메소드는 touch가 일어난 point를 포함하는 subview들 중 가장 먼 subview를 return한다. 바로 그 view가 first-responder가 되는것이다.
Altering The Responder Chain
: nextResponder 프로퍼티를 override해서 자신이 원하는 object를 nextResponder로 지정할 수 있다.
UIView는 이미 nextResponder를 override해서 사용하고 있다. 만약 UIView가 viewcontroller의 Root View라면, nextResponder를 viewcontroller로 지정하고 root view가 아니면 super view로 지정한다.
UIViewController도 마찬가지로 자신의 root view가 UIWindow의 root view라면 UIWindow로 next responder를 지정하고 그게 아니면 presenting ViewController로 지정한다.
Directing Input to a Specific Responder
: UIResponder를 상속받은 object들은 event를 받으면 firstResponder가 될 수 있다. 다만, UITextFiled, UITextView처럼 event를 받는 즉시 자동으로 firstResponder가 되는 경우가 있고, UIButton, UIView처럼 명시적으로 becomeFirstResponder 메서드를 호출해야 firstResponder가 되는 경우가 있다.
firstResponder가 되면 UIKit은 해당 object에 등록해논 input view를 display한다. UITextField, UITextView의 input view는 system keyboard view이다.
Programmatically Changing the First Responder
: 명시적으로 firstResponder로 지정하기 위해 becomeFirstResponder 메서드를 호출하면 UIKit은 해당 object가 firstResponder가 될 수 있는지 몇가지 체크를 한다.
1. 현재의 firstResponder object에게 canResignFirstResponder 메시지를 보내 firstResponder를 resign할 수 있는지 확인한다.
보통 대부분의 object들은 YES를 리턴하지만, 필요에 따라 NO를 리턴하게 하는 경우가 있다. 대표적으로 textField, textView가 invalid한 data를 포함했을 경우이다.
2. firstResponder로 지정하고자 하는 object에게 canBecomeFirstResponder 메시지를 보내 firstResponder가 될 수 있는지 확인한다.(default값이 NO다.)
Assigning an Input View to a Responder
: object가 firstResponder가 될 때 inputView를 띄우기 위해서는 해당 object에 inputView 또는 inputViewController 프로퍼티를 세팅해줘야 한다. inputView, inputViewController를 올바르게 사용하기 위해서 알아둬야할 몇가지가 있다.
1. inputView의 UI를 screen width에 맞춰서 구현해야 한다.
- UIKit은 screen width와 내가 지정한 높이로 input view의 size를 결정하기 때문이다.
2. delegate를 사용해서 inputView를 통해 들어온 data를 firstResponder에게 전해줘라.
3. keyboard notifications를 사용해라.
- system keyboard view뿐만 아니라 firstResponder의 inputView는 모두 keyboard notification들을 사용할 수 있다.
(UIKeyboardWillChangeFrameNotification, UIKeyboardWillShowNotification, UIKeyboardDidChangeFrameNotification, UIKeyboardDidShowNotification)
responder는 inputView이외에도 accessory view를 가질 수 있다. inputAccessoryView, inputAccessoryViewController 프로퍼티를 이용해서 지정한다. accessory view는 input view를 보조하는 역할을 한다. 예를들어 system keyboard view는 accessory view를 이용해서 자동완성 기능을 제공한다.
'IOS > 공통' 카테고리의 다른 글
Extension (0) | 2017.08.31 |
---|---|
Bundle Programming Guide (0) | 2017.06.11 |
Event Handling Guide - Gesture (0) | 2017.04.07 |
Objective-C, Swift 기초 (0) | 2017.03.26 |
Cocoa Pods (0) | 2017.02.19 |