Window and View
Window 와 View 의 관계는 아래의 그림을 보시면 쉽게 이해할 수 있습니다.
(출처 : iPhone Application Programming Guide)
iPhone 애플리케이션은 한개의 Window 와 여러개의 View를 갖습니다. 그리고 그 View 들은 또 다른 View들을 가지고 있습니다.
Layout of views (출처 : iPhone Application Programming Guide)
참고로 Window 의 크기는 iPhone 기준 320x480 의 크기를 갖고 있으며, Status Bar는 20x480,Navigation Bar와 Tab Bar는 44x480 의 크기를 갖고 있습니다. 상황에 따라 View 를 구성하시는데참고하시기 바랍니다.
UIWindow
Window는 UIWindow 클래스로 구현되어 있습니다. iPhone 애플리케이션은 구동시에 UIWindow 객체를 생성하여 사용자에게 화면을 보여주게 됩니다.
UIWindow 를 이용한 iPhone 애플리케이션을 작성하려면 단순히 Xcode 에서 iPhone 탭의 Window-Based 애플리케이션 프로젝트로 생성을 하면 됩니다.
실제로 Window-Based 애플리케이션으로 프로젝트를 생성하여 코드를 살펴보면, UIWindow 클래스의 인스턴스를 생성하는 부분이 없습니다.
인터페이스 빌더의 MainWindow.xib 파일에서 UIWindow 인스턴스가 정의되어 있기 때문에 따로 생성하지 않아도 아울렛이나 딜리게이터를 통해 사용이 가능합니다.
인터페이스 빌더를 사용하지 않고, UIWindow 를 생성하려면 UIApplication의 딜리게이터의applicationDidFinishLaunching 메소드에 다음과 같은 코드를 추가하여야 할 것입니다.(initWithFrame 메시지를 보내어 화면 크기만큼의 크기로 생성합니다.)
- UIWindow* aWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UIWindow의 인스턴스를 생성하였으면, 이제 Window 에 View를 추가할 차례입니다.
- UIView *view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
- [view setBackgroundColor:[UIColor redColor]];
- [window addSubview:view];
위의 코드를 수행하면 빨간 화면의 View가 Window에 추가되어서 보여지게 됩니다. 코드를 살펴보면, UIWindow와 같이 initWithFrame 으로 생성하는데 mainScreen이 아닌 applicationFrame 로 생성을 합니다.
이렇게 생성하면, statusBar 와 같은 Window 프로퍼티로 인한 크기를 제외한 실제 보여지는 화면 크기만큼으로 생성을 하게 됩니다.
View-Based Application
- Xcode 를 실행하고, iPhone 탭의 View-Based Application 를 선택하야 프로젝트를 생성합니다.
- 프로젝트의 왼쪽 Groups & Files 의 Resources 폴더를 살펴보면, xib 파일이 2개 존재 합니다.
- MainWindow.xib 는 UIWindow 를 구성하는 인터페이스 빌더 파일이고, 나머지 하나는{프로젝트이름}ViewController.xib 파일입니다. 이 파일은 UIWindow 에 추가되는 서브뷰의 인터페이스 빌더파일입니다.
- 이 파일을 더블클릭하여 인터페이스 빌더를 실행하고 Library 창에서 컨트롤을 드래그앤드랍 하여 다음과 같이 뷰를 구성합니다.
-
구성이 완료 되면 저장을 하고 Xcode 로 돌아와 {프로젝트이름}ViewController.h 파일과 {프로젝트이름}ViewController.m 파일을 다음과 같이 편집합니다.
- // ViewController.h 파일의 클래스 선언을 다음과 같이 수정
@interface ViewBasedViewController : UIViewController {
IBOutlet UITextField *textField;
}
- (IBAction)test:(id)sender;
@property (nonatomic, retain) IBOutlet UITextField *textField;
@end
// ViewController.m 파일에 다음의 메소드를 추가
- (IBAction)test:(id)sender
{
textField.text = @"test";
}
- // ViewController.h 파일의 클래스 선언을 다음과 같이 수정
- 편집이 완료 되었으면 다시 {프로젝트이름}ViewController.xib 파일을 열어서 인터페이스 빌더로 돌아갑니다.
- 버튼 영역 위에서 마우스 오른쪽 버튼을 누른 채로 File's Owner 로 드래그앤드랍 합니다.
- 해당 이벤트 메소드(여기서는 test: )를 선택하여, 액션을 연결합니다.
- 이번에는 File's Owner 위에서 텍스트 필드로 오른쪽 버튼을 누른 채로 드래그앤드랍을 하고, 해당 아울렛(여기서는 textField) 을 선택하여 아울렛을 연결합니다.
- 위의 연결 작업을 마치고 File's Owner 위에서 오른쪽 버튼을 누르면 다음과 같은 참조 상태를 확인 할 수 있습니다.
- 빌드 대상을 시뮬레이터로 전환하고 Build and Go 를 수행하면 다음과 같은 실행 결과를 확인 할 수 있습니다.
UIView
UIView 는 iPhone 애플리케이션 구조에서 MVC 모델 중 View 역할을 담당하고 아래와 같은 일들을 처리합니다.
- 화면을 그리거나 애니메이션 효과를 연출
- 레이아웃을 구성하거나 서브뷰들을 관리
- 터치 이벤트를 처리
단순히 iPhone SDK 에서 제공해주는 컨트롤들을 사용하여 애플리케이션을 구성한다면, 인터페이스 빌더를 이용하여 UIView 에 원하는 컨트롤을 추가하고, 아울렛을 연결하는 정도 만으로도 충분히 구현가능합니다.
하지만, 복잡한 UI 구성이나 퍼포먼스 개선을 위해서는 iPhone 애플리케이션의 드로잉 메카니즘을 이해하고 적절히 구현하여야 합니다.
iPhone 애플리케이션이 화면을 구성하는 Drawing Cycle 을 살펴보도록 하겠습니다.
UIView 객체가 화면 업데이트 요청을 받으면 UIView 객체는 drawRect: 메소드를 호출합니다.
이 때 인자로 갱신해야할 영역이 CGRect 구조체를 참고하여 해당 영역을 업데이트 합니다.
drawRect: 메소드는 다음과 같은 경우에 호출 되어집니다.
- 비활성화 영역이 생겼을 때
- UIView 의 hidden 프로퍼티가 YES에서 NO로 토글 되었을 때
- 스크롤에 의해 화면에 보여질 영역이 변경 되었을 때
- UIView 의 setNeedsDisplay: 메소드와 setNeedsDisplayInRect: 메소드가 호출 되었을 때
이런 경우에 drawRect: 메소드가 호출되므로 커스텀 뷰를 개발 할때에는 drawRect: 메소드를 호출 하는 횟수를 줄이고 내용을 최소화하여 퍼포먼스를 개선해야 합니다.
개선 방법은 iPhone SDK 문서에 상세히 써있으므로 생략합니다.
다음으로 iPhone 애플리케이션의 주 이벤트인 터치 이벤트 처리를 살펴보도록 하겠습니다. 터치 이벤트는 크게 4종류로 전달 됩니다.
- - (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
: 터치 이벤트가 시스템에 의해 취소되었을 때 발생 (예를들면 전화가 왔을때)
A multi-touch sequence and touch phases (출처 : iPhone Application Programming Guide)
터치이벤트는 touches 인자로 전달되며, NSSet 형태로 전달되어 싱글터치 및 멀티터치 처리가 가능합니다.
(싱글터치가 아닌 멀티터치를 처리하려면 multipleTouchEnabled 프로퍼티를 YES로 설정하거나, isMultipleTouchEnabled 메소드를 오버라이드 하여 YES 를 return 해주면 처리가 가능합니다.)
4가지의 이벤트는 Responder 에게 전달되며, 전달 규칙은 Responder Chain 에 의해서 전달 됩니다. 일반적으로는 UIView 가 이벤트를 가장 먼저 받게 됩니다.(First Responder)
Responder가 터치 이벤트를 처리하지 않았을때는, Next Responder 에게 이벤트를 보냅니다. UIView 경우에는 super view 에게 해당 이벤트를 보냅니다.
이런식으로 체인이 이루어지고 최종적으로 UIWindow가 이 이벤트를 받게되고, UIWindow는UIApplication으로 이벤트를 보냅니다. 이와같은 방식은 Chain of Responsibility 패턴을 참고하시기바랍니다.
애니메이션과 레이아웃에 관해서는 이번 튜토리얼에서는 생략하겠습니다. (추후 추가 예정)
UIViewController
UIView 에서 MVC 모델의 View 역할을 담당했다면, UIViewController 는 Controller 부분을 담당합니다.
UIView 에서는 UI적인 측면만 처리하고, UIViewController는 여러 Model 로부터 데이터를 불러오거나, 시스템으로부터 오는 여러 메시지들을 처리합니다.
loadView, viewDidAppear, viewDidDisappear, viewDidLoad,viewWillDisappear 등은 뷰의 상태에 따라 시스템으로부터 오는 메시지들입니다. 이런 메시지들을 처리하려면 해당메소드를 오버라이드 하여 처리하면 됩니다.
UIViewController의 view 프로퍼티에 원하는 커스텀 뷰를 설정하거나, 생성한 뷰를 설정하면 해당 뷰의 컨트롤러로 설정이 가능합니다.
특히, initWithNibName 이라는 초기화 메소드를 지원하여 인터페이스 빌더와 연동하여 개발을 할때에 주로 사용됩니다.
UIViewController의 sub class 로는 UITabBarController,UITableViewController, UINavigationController 가 있어서 각각 TabBar,TableView, NavigationBar 를 사용할때에 사용되어 집니다.
'개발 > App Developer' 카테고리의 다른 글
읽어보자-스마트폰과 위치기반서비스 (0) | 2010.09.01 |
---|---|
구조체(CGPoint,CGSize,CGRect) -> 객체(NSDictionary) -> 구조체 (0) | 2010.09.01 |
Enumeraion (0) | 2010.08.31 |
10.07.06 개발노트 (0) | 2010.08.31 |
10.07.08 스터디 (0) | 2010.08.31 |