Cocoa 와 Cocoa touch responder chain 이해하기

손명기
8 min readMar 26, 2017

--

https://medium.com/ios-os-x-development/understanding-cocoa-and-cocoa-touch-responder-chain-12fe558ebe97#.ibee4afmc 를 번역한 것입니다. 문제가 있을 시 삭제됩니다.

Cocoa 및 cocoa touch에 있는 application들은 하나의 event queue을 가집니다. 이 event queue는 다수의 다른 event로 부터 채워집니다. event의 stream을 처리하기 위해 각 application은 선입선출(first in first out)에 따라 event들을 채택하거나 전파하는 event run loop를 관리합니다.

application이 처음 실행되었을 때, UIApplicationMain를 호출하여 UIApplication 싱글톤 객체를 생성합니다. 이 객체는 system이 app event queue로 보내는 event를 처리하고 전달하는 작업을 담당합니다.

application는 다음으로 부터 event들을 수신받습니다:

  • UIControl Actions: action/target pattern을 사용하여 등록된 action
  • User events: touch, shake, motion 등등와 같은 user에 의한 event
  • System events: low memory, rotation 등와 같은 event

이러한 각 event는 해당 수신자에게 전달되기 전에 application에 의해 처리됩니다.

UIControl Actions

UIControl action들은 addTarget:action:forControlEvents: 메소드 호출하여 control에 추가된 action이며, UIControl은 추가된 모든 action/target 쌍을 기록합니다. user가 control에서 event를 수행하거나 UIControl이 sendActionsForControlEvents 함수를 호출하면, 해당 control event와 관련된 작업이 등록된 target으로 보내집니다.

예는 다음과 같습니다:

UIButton button = [UIButton new];[button addTarget:self action:@selector(buttonTapped) forControlEvents:UIControlEventTouchUpInside];

user가 button을 탭할때, event는 UIApplication으로 전달됩니다. application은 event queue에서 이 작업을 읽고 UIApplication sendAction:to:from:forEent: 함수에 전달합니다. 해당 메소드의 기본 구현은 등록된 target에 대한 작업을 호출합니다. target은 이 경우 buttonTapped 메소드를 받습니다.

만약 target을 nil로 설정했다면,

[button addTarget:nil action:@selector(buttonTapped) forControlEvents:UIControlEventTouchUpInside];

이 경우, sendAction:to:from:forEvent 기본 구현은 buttonTapped selector를 현재 first responder에게 보냅니다.

만약 first responder가 해당 action을 구현하지 않으면 (예, buttonTapped) 다음 responder에게 보내집니다. chain에 responder가 더 이상 없을 때까지 system은 responder chain에서 유효한 responder를 찾기 위해 계속 시도할 것입니다. 이 경우는 취소됩니다.

이 지식을 이용하여 우리는 first responder에게 UIApplication singleton 객체에 있는 sendAction:to:from:forEvent 메소드 호출로 action을 보낼 수 있습니다.

예를 들어, resignFirstResponder를 first responder에게 보내면 다음과 같이 keyboard를 종료할 수 있습니다.

[[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil];

User Events

User event들은(touch, device motion와 같은) application event queue에 전송됩니다. 만약 touch가 아닌 user event이라면, application이 first responder에게 호출을 전달하고, first responder가 system을 처리하지 못하면 responder-chain을 따라 적절한 responder를 찾습니다.

touch event들의 경우 흐름이 다릅니다. system이 화면에서 touch를 감지하면 이 touch를 application에 보내고 application은 _touchesEvent 내부 메소드에서 touch event를 받습니다.

그러면 application은 sendEvent를 사용하여 이 event를 UIWindow에 전달합니다. 이 event를 받으면 window는 이 touch를 받은 view를 찾기 위해 view hit-test process를 시작합니다.

UIView의 hitTest:withEvent는 touch 상태의 view를 찾는데 사용되며, hit-test의 구현은 touch가 view 범위 내에 있는지 확인합니다. 각 view는 pointInside:withEvent를 호출합니다.

hitTest와 pointInside는 최상위 left view에 도달할 때까지 재귀적으로 호출됩니다. 이 view는 touch event의 first responder로 사용됩니다.

그러면 UIWindow는 touch event를 이 view에 보냅니다.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

event가 view에 보내졌을 때, 이 view는 3가지 를 선택할 수 있습니다:

  • 위 4가지 메소드의 UIResponder 기본 구현은 다음 responder에게 event를 전달하므로 view가 메소드를 구현하지 않으면 이 메소드는 다음 responder에게 전달됩니다.
  • view는 위의 메소드를 구현하고, 일부 처리를 수행한 다음 responder가 추가 process를 수행할 수 있도록 super를 호출할 수 있습니다.
  • view는 위의 메소드를 구현할 수 있으며, event를 다음 responder에게 전달하지 않도록 선택할 수 있습니다.

만약 view가 touch event를 처리하지 않기로 선택하면, 이 경로를 따라 responder chain에 전송됩니다.

  • first responder는 hit-tested view입니다.
  • next responder는 이 view의 super view입니다.
  • chain은 view controller와 연결된 view에 도달할 때 까지 view 계층구조를 계속 합니다.
  • 해당 view controller가 next responder가 됩니다.
  • 만약 view controller가 root controller이라면, next responder가 됩니다.
  • application은 window의 next responder입니다.
  • chain의 마지막 responder는 app delegate입니다.

System Events

system은 event들을 application 싱글톤객체에게 보냅니다. 이러한 system 관련 event들은 application 싱글턴 객체에서 수신되어 application delegate에게 전달됩니다. Application delegate는 이 event를 수신하고 처리합니다.

The First responder

모든 UIResponder는 becomFirstResponder 메소드를 수신하거나 호출하여 first responder가 되도록 선택할 수있습니다. First responder는 user event가 수신될 때 이를 처리할 수 있는 기회가 주어집니다. 그러나 touch event는 first responder에게 전송되지 않으며 이러한 event는 재귀 hit-test를 통해 발견된 view로 전송됩니다.

--

--