- 솔리테어 카드게임을 구현한다.
- 더블탭과 드래그로 카드를 옮길 수 있다.
- 디바이스를 흔들면 (Shake Gesture)게임이 새로 시작된다.
- 게임을 완료하면 안내메시지를 표시한다.
- Custom View, Gesture Recognizer, View Animation, UIAlertController,
ViewModel 활용: 기존의 MVC를 유지하되, View를 Passive하게 만들고 View Model담당 객체를 추가
- 이 프로젝트에서 가장 깊이 경험했던 부분은 복잡한 뷰 계층구조에서 발생하는 이벤트 감지와 처리를 위해 최대한 효과적으로 로직을 분리하는 것이었습니다.
- 따라서 복잡한 계층 구조를 가진 객체의 역할을 분리하고, 최대한 Passive한 View를 만들어서 View Model만으로도 게임 로직이 성립되도록 구현했습니다.
- 또한 이벤트 수신과 처리에 대한 결과를 반영하기위한 View update flow의 단방향성에 신경써서 작업하였습니다.
- 카드의 위치에 따라 Foundation, CardDeck, CardStack으로 객체 역할 구분
- 카드게임 전체를 관할하는 CardGameManager 클래스를 Singleton객체로 설계하여 하나의 앱 당 하나의 CardGameManager만 존재하도록 구현하고, 게임이 재시작됐을때 새롭게 초기화된 게임매니저 객체를 할당
- CardGameManager: 카드게임 전체를 관할하는 모든 모델들의 최상위모델
- Card: 카드한장을 나타내는 객체
- CardDeck: 52장의 카드를 모아두는 카드덱
- CardStack: 필드에 놓여진 카드 스택 하나
- DeckManager - CardDeckView: CardDeck에 있는 카드뷰들을 담당
- WholeStackManager - CardStacksView: 전체 CardStack 7개를 담당
- StackManager - OneStack: CardStack 1개를 담당
- FoundationManager - FoundationView: Foundation 담당 (카드가 순서대로 맞춰져서 쌓이는 곳)
- FrameCalculator: 각 서브뷰에서 수신되는 이벤트(DoubleTap, PanGesture)에 따른 카드뷰들의 위치를 계산하는 객체
- (카드게임앱은 하나의 루트뷰를 Deck, Foundation, Stack의 세 영역으로 나누고 프레임을 계산해서 서브뷰를 띄운 방식으로 구현함. 따라서 ViewController가 제스처를 수신하고 이벤트를 처리할때 복잡한 프레임 계산을 담당하는 객체가 필요했음.)
Handling UIKit Gestures 번역한 것 블로그에 정리
- 사용자는 디바이스에서 특정 액션을 취함 (터치, 줌 등)
- 그 액션에 해당하는 이벤트가 시스템에 의해 생성, UIKit에서 생성한 port를 통해 앱에 전달
- 이벤트들은 앱 내부적으로 queue에 저장(FIFO)
- UIApplication객체가 가장 먼저 이 이벤트를 받아서 어떤 동작이 취해질 지 결정
- 터치 이벤트의 경우 main window객체가 인식하고 window객체가 다시 터치가 발생한 view로 이벤트를 전달함
- 다른 이벤트들도 다양한 app객체에 따라 조금씩 다르게 동작
- Touch이벤트: 터치 이벤트가 발생한 view객체 로 전달
- view는 응답을 할 줄 아는(Responder) 객체이므로 터치 이벤트가 발생한 뷰 객체로 전달됨. 만약 해당 뷰에서 처리되지 않는 터치이벤트는 Responder chain을 따라 계속 내려가게됨
- Remote control / Shake motion events: First responder object객체
- 미디어콘텐츠의 재생이나 되감기 등과같은 remote control이벤트는 주로 헤드폰같은 악세사리에서 발생
- Redraw: 업데이트가 필요한 객체
- Redraw 이벤트는 이벤트 객체를 갖지는 않고, 단순히 업데이트가 필요한 view객체에 요청
- 참고, 이벤트 소스 종류
- 입력소스(input source): 다른 thread나 어플리케이션에서 전달되는 메시지 이벤트(비동기식)
- 타이머소스(timer source): 예정시간이나 반복수행간격에 따라 발생하는 이벤트(동기식)
- Touch나 Remote Control 같은 이벤트는 앱의 Responder객체를 통해 처리된다.
- Responder객체는 앱의 모든 곳에 존재
- UIApplication, 커스텀 view객체, ViewController객체 모두 Responder객체에 해당된다.
Touches, Presses, and Gestures UIResponder객체는 앱의 이벤트를 핸들링한다. 사용자로부터 입력되는 터치나 제스쳐 이벤트는 UIEvent객체로써 앱과 연결된다.
-
UIResponder- An abstract interface for responding to and handling events.
-
UIEvent - An object that describes a single user interaction with your app.
-
Touches : Handling Touches in Your View
-
Gestures(press, tap): Handling UIKit Gestures