[iOS Study] 터치 이벤트와 UIResponder |
출처 : 아론 힐리가스의 iOS 프로그래밍
-
UIView 는 UIResponder 의 하위 클래스로서 각각 다른 터치 이벤트를 처리할 네 개의 메소드를 재정의할 수 있다.
- (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;
-
화면을 손가락으로 터치하면 UITouch 인스턴스가 만들어진다.
터치한 UIView 는 touchesBegan:withEvent: 메시지를 받고 이 때 만들어진 UITouch 는 NSSet 타입의 touches 인자에 담긴다.
-
화면에서 손가락을 움직이면 터치 객체는 손가락의 현재 위치를 저장하기 위해 갱신된다.
그리고 터치가 시작된 UIView 에 touchesMoved:withEvent: 메시지가 보내진다.
이 메소드에 인자로 전달된 NSSet 은 화면을 터치한 손가락을 나타내는 원래 생성된 UITouch 를 가진다.
-
화면에서 손가락을 떼면 터치 객체는 마지막으로 손가락의 위치를 저장하기 위해 갱신된다.
그리고 터치가 시작된 뷰에 touchesEnded:withEvent: 메시지가 보내진다.
이 메소드가 완료된 후 UITouch 객체는 소멸된다.
-
화면에서 하나의 UITouch 는 한 개의 손가락에 대응한다.
이 터치 객체는 손가락이 화면에 있는 한 존재하고 항상 화면상의 손가락 위치를 포함한다.
-
터치가 시작된 뷰는 무슨 일이 있어도 그 손가락에 관한 모든 터치 이벤트 메시지를 받는다.
만약 손가락을 처음 터치한 UIView 의 frame 밖으로 움직이더라도 그 뷰는 여전히 touchesMoved:withEvent: 와 touchesEnded:withEvent: 메시지를 받는다.
따라서 터치가 뷰에서 시작되면 그 뷰는 터치 객체의 생존 동안 그 터치를 소유한다.
-
절대 UITouch 객체에 대한 참조를 유지해서는 안 된다.
프로그램은 터치 상태가 변경될 때 터치 객체에 대한 접근 기회를 줄 것이다.
-
터치가 뭔가를 할 때마다(터치 시작, 이동, 종료 등) 터치 이벤트가 UIApplication 객체가 관리하는 이벤트 큐에 추가된다.
실제로 큐는 좀처럼 가득 차지 않고 이벤트는 즉각 전달된다.
터치 이벤트의 전달은 터치를 소유한 뷰에 UIResponder 메시지 중 하나를 보내는 것을 포함한다.
(터치가 느리게 반응하면 메소드 중 하나가 CPU 를 점유하고 있는 것이다.
그리고 이벤트는 전달되기를 기다리며 대기한다.)
-
만약 정확히 같은 시간에 하나의 뷰에 여러 손가락으로 똑같이 터치한다면 이들 터치 이벤트 모두가 한 번에 전달된다.
손가락 수만큼의 터치 객체가 NSSet 에 포함되어 UIResponder 메시지에 인자로 전달된다.
하지만 윈도우에서 “정확히 같은 시간”이란 굉장히 짧다.
따라서 모든 터치를 가진 하나의 리스폰더 메시지 대신에 보통 하나 이상의 터치를 가진 여러 리스폰더 메시지가 올 것이다.
-
UITouch *t = [touches anyObject]; // UITouch 얻어오기
CGPoint location = [t locationInView:self]; // View 에서의 터치 위치 얻기
-
기본적으로 뷰는 한 번에 하나의 터치만을 허용한다.
만약 손가락 하나가 이미 touchesBegan:withEvent: 메시지를 보냈지만 끝나지 않았다면 touchesEnded:withEvent: 는 실행되지 않는다.
그리고 뒤이은 터치들은 무시된다.
여기서 “무시”는 View 에 touchesBegan:withEvent: 메시지나 추가적인 터치와 관련된 다른 UIResponder 메시지가 보내지지 않는 것을 의미한다.
-
멀티터치를 허용하려면. self.multipleTouchEnabled = YES; 를 수행해줘야 한다.
-
단일 터치뷰에서는 집합에 오직 한 객체만 들어있다.
따라서 어떤 객체를 위한 요청은 항상 이벤트가 발생한 터치를 전해줄 것이다.
반면 멀티 터치뷰에서는 집합이 하나 이상의 터치를 포함하고 있다.
-
NSDictionary 에서 키로 사용되는 객체는 반드시 NSCopying 프로토콜을 따라야 한다.
이 프로토콜은 copy 메시지를 보내서 그 객체들을 복사하도록 허용한다.
UITouch 인스턴스는 복사될 필요가 없기 때문에 이 프로토콜을 따르지 않는다.
따라서 NSValue 인스턴스가 이후에 같은 UITouch 를 가진 동일한 NSValue 인스턴스가 만들어질 수 있으므로 UITouch 의 주소를 가진다.
( [NSValue valueWithNonretainedObject:UITouch] )
-
touchesMoved:withEvent: 와 같은 UIResponder 메시지가 뷰에 보내질 때,
오직 이동된 터치들만 NSSet 에 존재한다는 것을 알고 있어야 한다.
-
UITouch 가 일단 뷰에서 시작되면 모든 터치 이벤트는 터치를 시작한 뷰에서 터치가 벗어나더라도 터치의 생존 기간 동안 항상 같은 뷰에 보내진다.
-
NSLog(@“%@“, NSStringFromSelector(_cmd));
위의 명령문은 호출되는 class 와 method 등을 출력하는 유용한 녀석
-
UIResponder 는 터치 이벤트를 받을 수 있다.
UIView 도 UIResponder 하위 클래스의 한 예이다.
그 밖에 UIViewController, UIApplication, UIWindow 를 포함해 많은 클래스들이 있다.
-
UIViewController 에 직접 터치 이벤트를 보낼 수 없다.
하지만 뷰 컨트롤러는 리스폰더 체인(responder chain)을 통해 이벤트를 받을 수 있다.
-
모든 UIResponder 는 nextResponder 라는 포인터를 가지며 이들 객체가 함께 리스폰더 체인을 구성한다
터치 이벤트는 터치된 뷰에서 시작한다.
뷰의 nextResponder 는 보통 자신의 UIViewController(뷰 컨트롤러가 있다면)이거나 상위뷰(뷰 컨트롤러가 없다면)이다.
뷰 컨트롤러의 nextResponder 는 보통 자신의 뷰의 상위뷰이다.
최상위뷰는 윈도우이다.
윈도우의 nextResponder 는 UIApplication 의 싱글톤 인스턴스이다.
-
UIResponder 는 동일한 메시지를 nextResponder 에게 전달한다.
이것이 바로 touchesBegan:withEvent: 와 같은 메소드의 기본 구현이 하는 일이다.
메소드를 재정의하지 않으면 그 다음 리스폰더가 터치 이벤트의 처리를 시도한다.
만약 프로그램(리스폰더 체인의 마지막 객체인)이 그 이벤트를 처리하지 못하면 터치 이벤트는 버려진다.
-
다음 리스폰터에게 명시적으로 메시지를 보낼 수도 있다.
[[self nextResponder] touchesBegan:touches withEvent:event];
-
코코아 터치에서 UIControl 클래스는 UIButton 과 UISlider 를 포함해 여러 클래스의 상위 클래스이다.
UIControl 에서 각각의 가능한 컨트롤 이벤트(control event)는 상수와 관련 있다.
버튼은 일반적은 UIControlEventTouchUpInside 컨트롤 이벤트에 관한 액션 메시지를 보낸다.
이 컨트롤 이벤트에 등록된 타깃은 사용자가 컨트롤을 터치했다가 그 컨트롤 프레임 안에서 손가락을 뗀 경우에만 액션 메시지를 받는다.
타깃과 액션을 할당하는 프로그램 코드는..
[aButton addTarget:tempController
action:@selecotr(resetTemperature:)
forControlEvent:UIControlEventTouchUpInside | UIControlEventTouchUpOutside];
-
CGRectContainsPoint(CGRect, CGPoint) 를 통해서 rect 안에 point 가 들어있는지 확인할 수 있다.
-
sendActionsForControlEvents: 는 컨트롤이 가진 모든 타깃-액션 쌍을 확인한다.
그리고 만약 어떤 타깃-액션이 인자로 전달된 컨트롤 이벤트에 등록되어 있다면 그 타깃은 액션 메시지를 받는다.
-
컨트롤은 절대 타깃에 직접 메시지를 보내지 않는다.
그 대신에 UIApplication 객체를 통해 이들 메시지를 보낸다.
컨트롤이 nil 타깃 액션을 가질 수 있기 때문이다.
UIControl 의 타깃이 nil 이면 UIApplication 은 그 UIWindow 의 퍼스트 리스폰더를 찾아 액션 메시지를 보낸다.
cf) 시뮬레이터에서는 option 키를 누른채 드래그하여 멀티 터치를 흉내 낼 수 있다.
'프로그래밍 놀이터 > iOS' 카테고리의 다른 글
[iOS Study] 디버그 도구 (0) | 2016.02.26 |
---|---|
[iOS Study] UIGestureRecognizer 와 UIMenuController (0) | 2016.02.25 |
[iOS Study] 카메라 (0) | 2016.02.23 |
[iOS Study] UINavigationController (0) | 2016.02.22 |
[iOS Study] UITableView 편집 (0) | 2016.02.21 |
댓글