이번에는 CoreData를 이용하는 간단한 샘플을 만들어 보겠습니다. 이전에 Xcode 2.*대에서 이와 비슷한 어플리케이션을 만드는 "간단한 ToDo 어플리케이션 만들기"란 포스팅을 한적이 있습니다. 소스코드에 추가 없이 마우스 클릭만으로 간단히 만드는 예제였는데 Xcode 3에서는 그 마우스 클릭도 최소한으로 줄이고 자동화여, 누구나 쉽게 간단한 어플리케이션을 만들 수 있습니다.

Core Data에 대한 자세한 내용은 아래의  ADC 문서들을 참조하시기 바랍니다.



1. 프로젝트 생성
Xcode를 실행하고 새로운 프로젝트를 생성하기 위해 메뉴에서 File / New Project.. 를 클릭합니다. 아래와 같이 Mac OS X / Application 항목에서 Core Data Document-based Application을 선택하고 Choose...를 클릭합니다.
프로젝트명에 'BookList'를 입력하고 save 버튼을 클릭하여 완료합니다.


2.  Data Model
1) Data Modeling tool
좌측과 같이 Xcode의 Groups & Files아래에 BookList / Models에서 MyDocument.xcdatamodel을 더블클릭합니다.

아래와 같은 데이터 모델링 툴이 오픈됩니다.
2) Entity 추가
위의 이미지에서 붉은색 화살표가 가르키는 Entity 항목 하단의 + 버튼을 클릭하여 새로운 Entity를 추가합니다. 생성된 항목을 더블클릭하거나 우측의 설정창에서 Name: 항목의 입력창을 이용하여 아래와 같이 'Books'로 이름을 변경합니다.


3) Attribute 설정
* 추가
이제 Books에 속성(Attribute)를 추가합니다. Property창 하단의 + 버튼을 클릭하여 나오는 항목중 Add Attrribute를 클릭합니다. 2번 더 반복하여 3개의 속성을 생성합니다.

* 설정
속성들의 이름을 각각 titile, writer, press로 입력하고 아래와 같이 항목들을 설정합니다.




3. 인터페이스 빌더
Xcode에서 MyDocument.xib를 더블클릭하여 인터페이스 빌더를 오픈합니다. 먼저 윈도우에 기본으로 생성되어 있는 "Your document contetents here'  라벨을 삭제합니다.

그리고 라이브러리 윈도우의 Cocoa / Objects & Controllers / Core Data 항목에서 좌측과 같은 Core Data Entity를 드래그하여 윈도우로 가져다 놓습니다.



1) Core Data Entity 생성
윈도우로 드래그를 완료하면 설장창이 오픈됩니다. 아래와 같이 entity를 Books로 선택하고 Next 버튼을 클릭하고 각 단계별로 아래와 같이 진행합니다.
2) 윈도우 크기 조절
생성된 항목에 맞추어 아래와 같이 윈도우의 크기를 적당히 조절합니다.

4. Build & Test
현재까지의 작업만으로 기본적인 동작을 수행할 수 있는 작업이 완료되었습니다. 이제 빌드를 하고 어플리케이션을 실행하여 테스트 합니다.
어플리케이션이 실행되면 등록, 변경, 삭제, 검색 등과 파일 저장/오픈이 동작하는지 확인합니다.


'Xcode 3 > 튜토리얼' 카테고리의 다른 글

2. 간단한 Core Data 예제  (9) 2008.10.05
1. Xcode3 첫 어플리케이션  (17) 2008.09.26

Xcode3 에서 간단한 코코아 UI 샘플을 만들어 보는 튜토리얼입니다. 아래와 같이 하나의 입력 창과 세개의 버튼을 가진 간단한 어플리케이션 입니다.

각각의 버튼들의 기능은 아래와 같습니다. 라벨의 이동시에는 animator를 이용해 간단한 효과를 주었습니다.

텍스트에 입력된 내용을 상단의 라벨에 출력합니다.

라벨이 원래 있던 좌측의 위치로 이동하도록 합니다.

라벨이 우측 끝으로 이동하도록 합니다.


1. 프로젝트 생성
Xcode를 실행하고 메뉴에서 File/New Project...를 클릭합니다. 좌측에서 Mac OS X/Application을 선택하고 Cocoa Application 템플릿을 선택한 후, Choose... 버튼을 클릭합니다. 

(iPhone SDK 설치되어 있지 않으면 좌측의 메뉴가 조금 다를 수도 있습니다)

프로젝트가 저장될 디렉토리를 선택한 후에 프로젝트명(Control1)을 입력하고 Save 버튼을 클릭합니다.



2. 인터페이스 빌더
1) 인터페이스 빌더 실행
좌측과 같이 Xcode의 Groups & Files/Resources의 MainMenu.xib를 더블클릭하여 인터페이스 빌더를 실행합니다.







2) 라이브러리 윈도우
인터페이스 빌더의 메뉴에서 Tools/Library를 클릭하거나 단축키(Shift+Command+L)를 이용하여 아래와 같은 라이브러리 윈도우를 오픈합니다. 이 윈도우 하단의 아이템중에서 필요한 각종 오브젝트나 컨트롤들을 원하는 위치에 드래그하여 사용할 수 있습니다.



3) 윈도우
라이브러리 윈도에서 아래와 같이 Label, Text Field, Push Button을 드래그 해서 윈도우에 아래와 같이 배치하고 윈도우 크기를 적당하게 조절합니다.


라이브러리 윈도우에서 각 컨트롤의 위치는 아래와 같습니다.

  • Label - Cocoa / Views & Cell / Input & Values
  • Text Field - Cocoa / Views & Cell / Input & Values
  • Puish Button - Cocoa / Views & Cell / Buttons


3. AppController
1) 소스파일 생성
다시 Xcode로 돌아와 Groups & Files에서 Classes를 우클릭을 하거나 단축키(Command+N)를 이용하여 파일생성 창을 오픈합니다.


Mac OS X/Cocoa에서 Objective-C class를 선택하고 Next 버튼을 클릭합니다.

파일명에 AppController.m을 입력하고 Finish 버튼을 클릭합니다.

좌측과 같이 AppController.h와 AppController.m 소스 파일이 Classes 아래에 생성되었습니다.

먼저 AppController.h를 클릭하여 소스를 변경합니다.


2) AppController.h
헤더 파일에서 아래에 푸른색으로 되어 있는 부분을 입력합니다.
#import <Cocoa/Cocoa.h>

@interface AppController : NSObject {
    IBOutlet NSTextField    *textLabel;
    IBOutlet NSTextField    *inputField;
   
    IBOutlet NSButton    *refreshButton;
    IBOutlet NSButton    *leftButton;
    IBOutlet NSButton    *rightButton;

    NSPoint    originalPoint;
}

- (IBAction)setLabel:(id)sender;
- (IBAction)moveLeft:(id)sender;
- (IBAction)moveRight:(id)sender;

@end

인터페이스 빌더에서 생성한 각각의 컨트롤들을 연결하기 위해 IBOutlet 변수와 버튼을 클릭했을 경우에 처리할 IBAction 메소드를 선언합니다.

3) AppController.m
 소스코드에서 아래에 푸른색으로 되어 있는 부분을 입력합니다.
#import "AppController.h"

@implementation AppController

- (void)awakeFromNib {
   
    // 버튼 이미지를 지정
    NSImage *buttonImage = [NSImage imageNamed:NSImageNameRefreshTemplate];
    [refreshButton setImage:buttonImage];

    buttonImage = [NSImage imageNamed:NSImageNameGoLeftTemplate];
    [leftButton setImage:buttonImage];
   
    buttonImage = [NSImage imageNamed:NSImageNameGoRightTemplate];
    [rightButton setImage:buttonImage];
   
    originalPoint = [textLabel frame].origin;
}

- (IBAction)setLabel:(id)sender {
   
    // 입력한 문자를 라벨에 지정하고 라벨의 크기를 문자열의 길이만큼 변경
    [textLabel setStringValue:[inputField stringValue]];   
    [textLabel sizeToFit];
}

- (IBAction)moveLeft:(id)sender {
   
    // 라벨을 초기 위치로 이동
    [[textLabel animator] setFrameOrigin:originalPoint];
}

- (IBAction)moveRight:(id)sender {
    CGFloat xPos;
   
    // 우측 모서리로 이동하도록 윈도우의 크기에서 라벨의 크기를 뺀 위치로 설정
    xPos = [[[NSApp mainWindow] contentView] bounds].size.width;
    xPos -= [textLabel frame].size.width;
   
    // 에니메이션과 함께 라벨의 위치 변경
    NSPoint targetPoint = NSMakePoint(xPos, originalPoint.y);
    [[textLabel animator] setFrameOrigin:targetPoint];
}

@end


4. 연결
다시 인터페이스 빌더로 돌아 가서 작업을 마무리 합니다

1) AppController 인스턴스 생성
라이브러리 윈도우에서 좌측과 같은 Object를 MainMenu.xib 윈도우로 드래그해서 가져다 놓습니다.

Object는 라이브러리 윈도우에서 Cocoa / Objects & Controllers / Controllers내에 있습니다.

아래와 같이 Object가 생성된 것을 확인하시고 Object가 선택된 상태에서 인터페이스 빌더의 Tools/Inspector 메뉴를 클릭하거나 단축키 (Shift + Command + I)를 이용하여 Inspector 창을 오픈합니다.

Inspector 창에서 좌측과 같이 6번째에 있는 App Controller Identity를 선택합니다. (단축키: Command + 6)

Class메뉴의 콤보박스를 클릭하고 Xcode에서 이전 단계에서 생성한 AppController를 선택합니다.


2) 연결
MainMenu.xib 창에서 App Controller를 선택한 상태에서 마우스 우클릭을 하면 아래와 같이 연결 창이 오픈됩니다.


연결창의 각 항목 좌측에 있는 원 모양의 영역에 마우스를 가져가면 우측과 같이 '+' 모양으로 변경됩니다. 이 상태에서 마우스로 '+'를 클릭한 후에 드래그 하여 각각의 해당 항목들에 연결합니다.

마우스를 클릭한 상태에서 파란색 선을 연결할 컨트롤로 가져가면 아래와 같이 컨트롤의 이름과 함께 선택되었을 때 마우스 클릭을 해제합니다.


이런 방식으로 Outlet과 Action을 각각의 컨트롤들과 연결합니다.

  • Outlets / inputField -> Text Field 
  • Outlets / textLabel -> Label
  • Outlets / refreshButton -> Button (첫번째)
  • Outlets / leftButton -> Button (두번째)
  • Outlets / rightButton -> Button (세번째)

  • Received Actions / setLabel -> 버튼 (첫번째)
  • Received Actions / moveLeft -> 버튼 (두번째)
  • Received Actions / moveRight -> 버튼 (세번째)

작업이 완료되면 아래와 같이 연결되었는지 확인합니다.

 
3) 빌드 및 테스트
이제 모든 작업이 완료되었습니다. 인터페이스 빌더와 Xcode에서 변경된 내용을 저장하고, Xcode에서 좌측의 툴바를 클릭하거나 단축키(command + R)를 이용하여 빌드하고 테스트 해 봅니다.


Xcode를 처음 해보시는 분들도 따라 하실 수 있게 최대한 자세하게 설명을 할려고 했습니다. 하지만 제 생각대로 처음 하시는 분들도 무리없이 하실 수 있을지는 잘 모르겠습니다.

잘 안되시는 분들은 아래의 프로젝트 파일을 다운로드 받아서 비교해 보시기 바랍니다.

'Xcode 3 > 튜토리얼' 카테고리의 다른 글

2. 간단한 Core Data 예제  (9) 2008.10.05
1. Xcode3 첫 어플리케이션  (17) 2008.09.26

이전 장에 이어서 이제 인터페이스빌더에서 작업을 하고 어플리케이션을 완성해 보겠습니다. 속성 변경 및 연결에 관한 자세한 설명을 생략하였습니다. 혹시 이부분에 이해가 가지 않으시면 이전 포스팅을 참고하시기 바랍니다.

3. MainView.xib
1) 이미지 추가
어플리케이션에서 사용하는 배경과 각종 이미지들을 프로젝트에 추가합니다. 사용된 이미지는 아래의 압축파일을 다운로드하여 사용하시거나 직접 그려서 사용하셔도 됩니다.


Xcode의 Groups & Files내의 Resources 디렉토리를 우클릭 한후에 Add/Existing Files...를 클릭합니다.  파일 선택창에서 배경과 아이콘들을 선택한 다음 Add 버튼을 클릭합니다. 그리고 MainView.xib 항목을 더블클릭 하여 인터페이스빌더를 엽니다. 라이브러리의 Media 탭을 클릭하면 등록된 이미지를 확인할 수 있습니다.


2) 레이아웃
라이브러리 윈도우에서 각각의 오브젝트들을 드래그해서 아래와 같이 Main View에 배치합니다. 이미지도 위의 라이브러리 윈도우에서 드래그해서 가져옵니다. 주의하실 점은 눈에 보이지 않더라도 하단 툴바의 중앙에 Bar Button Item이 있습니다.
 


3) 속성 변경 및 연결
이제 각 항목의 속성을 변경하고 아울렛을 연결하는 작업을 해보겠습니다. 각 오브젝트와의 연결은 MainView.xib의 File's Owner (MainViewController)를 우클릭하여 설정합니다. 

* MainView
배경색을 원하시는 색상으로 변경합니다.


File's Owner의 mainView 아울렛에 연결합니다.


* Navigation Bar
상단바의 타이틀을 더블클릭하여 좌측과 같이 변경합니다.


* View
월별로 바이오리듬 그래프를 보여주는 View 입니다.
배경색을 검정으로 변경합니다. 실행시에는 배경이미지로 대체되기 때문에 큰 의미는 없습니다(생략가능).

Class 항목을 이전 장에서 만들어 두었던 GraphView를 선택합니다.

File's Owner의 graphView 아울렛에 연결합니다.


* TextField
일별로 바이오리듬 보여주는 필드입니다. 3개 모두 아래와 같이 설정합니다.
정렬을 중앙으로 설정합니다.

사용자의 입력에 반응하지 않도록 선택을 해제합니다.

위에서 부터 차례로 File's Owner의 value_1, value_2, value_3 아울렛과 연결합니다.


* Bar Button Item
버튼들을 더블클릭하여 좌측과 같이 입력상태가 되면 각각 "<<", "<", ">", ">>"을 입력합니다.

각 버튼을 구별할 수 있도록 속성창 하단에 위치한 Tag를 설정합니다. "<<"는 1, "<"는 2, ">"는 3, ">>"는 4를 각각 입력합니다.

네 버튼 모두 File's Owner의 NavigationButtonClicked: 액션에 연결합니다.


* 날짜 표시 Bar Button Item
현재 선택된 날짜를 표시하는 툴바의 중앙에 위치한 버튼 아이템입니다. Plain 스타일에 타이틀이 없기 때문에 위의 이미지에서 툴바와 구별되지 않았습니다.
 
스타일을 Plain으로 설정합니다. 버튼 스타일로 출력되지 않습니다.

사용자의 입력을 받지 않기 위해 선택을 해제합니다.

File's Owner의 currentDate 아울렛에 연결합니다.


File's Owner의 연결상태는 아래와 같습니다.



4. FlipsideView.xib
1) 레이아웃
라이브러리 윈도우에서 Label과 Date Picker를 드래그해서 아래와 같이 Flipside View에 배치합니다.


2) 속성 변경 및 연결
* Label
텍스트를 "생일을 선택해 주세요." 로 변경합니다.

텍스트 색상을 흰색으로 변경합니다.



* Date Picker
Date Picker의 Mode를 Date로 설정합니다.


유효날짜를 설정합니다.


File's Owner의 datePicker 아울렛에 연결합니다.


Files's Owner의 연결상태는 아래와 같습니다.


5. MainWindow.xib
MainWindow.xib에서 Root View Controller를 더블클릭합니다. 해당 창의 우측 하단을 보시면 좌측과 같은 버튼이 있습니다. 기본 위치가 툴바의 위치와 맞지 않기 때문에 위치를 우측과 아래로 더 이동합니다. 


6. 테스트
이제 모든 작업을 완료하였습니다. 모두 저장하고 빌드한 후에 테스트를 해봅니다. 아래와 같이 정상적으로 바이오리듬이 출력되고 버튼이 동작하는지 확인합니다.



이상으로 간단한 바이오리듬 어플리케이션을 만들어 보았습니다. 혹시 이상한 점이 있으시면 아래의 소스파일을 다운로드 받아서 비교해 보시기 바랍니다.


이번에는 저번 바이오리듬 보다 조금 기능을 추가하여 만들어 보겠습니다. 상단에는 한달 단위로 그래프를 보여주고, 하단에는 해당일의 바이오리듬 정보를 보여 줍니다. 그리고 생일설정을 저장할 수 있도록 하겠습니다. 하단 버튼들의 기능은 아래와 같습니다.

  • << : 한달 전으로 이동
  • < : 하루 전으로 이동
  • > : 하루 후로 이동
  • >> : 한달 후로 이동
  • i : 생일 설정 

한가지 오류가 있습니다. 생일설정 시에 기존의 저장된 날짜가 DatePicker에 설정되지 않습니다. 값은 정확한데 보여지는 부분은 minimumDate로 초기에 선택되어져 있는 것 같습니다. 검색을 해봐도 같은 증상을 겪은 경우는 보았는데, 원인과 해결책은 찾지 못했습니다.


완성된 모습은 아래와 같습니다.

사용자 삽입 이미지


1. 프로젝트 생성
사용자 삽입 이미지
Xcode의 메뉴에서 File/New Project 클릭합니다. iPhone OS의 applicaion에서 좌측과 같은 Unility Application을 선택하고 Choose 버튼을 클릭합니다. 프로젝트 이름에 'iBiorhythm'을 입력한 후에 저장합니다.

Unility Application은 컨텐츠를 보여주는 main view와 설정등을 할 수 있는 flipside view를 제공하며, 두 뷰의 변환시에 아래와 같은 에니메이션 효과를 제공합니다.

사용자 삽입 이미지

사용자 삽입 이미지
Xcode의 Groups & Files를 보시면 좌측과 같이 그룹이 생성되어 있습니다. MainView, FlipsideView 각각에는 view와 view를 관리하는 controller 소스들이 있습니다.


2. 소스코드 
1) Global.h
사용자 삽입 이미지
여러 소스에서 사용할 상수나 변수등을 위해 헤더 파일을 하나 만듭니다. File/New File...을 클릭합니다. Mac OS X에서 C and C++ 항목을 클릭하고 좌측과 같은 Header File이란 아이콘을 선택한 후에 파일명을 Global.h로 입력하고 저장합니다. 생성된 파일에 아래와 같은 내용을 추가 합니다.

#define    MAX_DATATYPE            3

#define US_BIRTHYEAR_KEY        @"birth_year"
#define US_BIRTHMONTH_KEY     @"birth_month"
#define US_BIRTHDAY_KEY          @"birth_day"

#define NM_BIRTHDAYCHANGED   @"NTBirthdayChanged"

#define NAV_PREVMONTH            1
#define NAV_PREVDAY                 2
#define NAV_NEXTDAY                 3
#define NAV_NEXTMONTH            4

#define ONEDAY_SECOND            (24 * 60 * 60)

2) GraphView
그래프를 출력하기 위한 View를 생성합니다. 메뉴에서 File/New File...을 클릭 후에 iPhone OS/Cocoa Touch Classes 항목에서 UIView subclass를 선택한 후에 Next 버튼을 클릭합니다. 파일명에 GraphView.m을 입력한 후에 저장합니다.

* GraphView.h
#import <UIKit/UIKit.h>

@interface GraphView : UIView {
    UIImage                *backgroundImage;
   
    NSDateComponents    *currentDate;
    NSDateComponents    *birthDate;
   
    float biorhythmData[31][MAX_DATATYPE];
}

@property (nonatomic, retain) NSDateComponents *currentDate;
@property (nonatomic, retain) NSDateComponents *birthDate;

- (void)setBirthDate:(int)year atMonth:(int)month atDay:(int)day;
- (void)setCurrentDate:(int)year atMonth:(int)month atDay:(int)day;
- (void)changeDate:(int)pos;

- (NSDateComponents *)currentDate;

- (void)resetBiorhythmData;
- (float *)getBiorhythmDayData:(int)day;

@end

* GraphView.m
#import "Global.h"
#import "GraphView.h"

@implementation GraphView

@synthesize currentDate;
@synthesize birthDate;

- (id)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
    }
    return self;
}

- (void)awakeFromNib {
    currentDate = [[NSDateComponents alloc] init];
   
    /* 배경 이미지로 사용할 bio.png 로드 */
    backgroundImage = [[UIImage alloc] initWithContentsOfFile:
                       [[NSBundle mainBundle] pathForResource:@"bio" ofType:@"png"]];
}

- (void)drawRect:(CGRect)rect {
#define START_X            17    // 그래프 시작 X 위치
#define START_Y            22  // 그래프 시작 Y 위치
#define DAY_WIDTH        10  // 일별 간격
#define BOTTOM_HEIGHT    4   // 하단 공백 높이

    /* 데이터별 색상 테이블 */
    static const CGFloat color[MAX_DATATYPE][5] = {
        { 1.0, 0.0, 0.0, 1.0 }, //red
        { 0.0, 1.0, 0.0, 1.0 }, //green
        { 0.0, 0.0, 1.0, 1.0 }  //blue
    };
   
    CGSize viewSize = rect.size;
    CGContextRef context = UIGraphicsGetCurrentContext();

    /* 배경 이미지 출력 */
    CGPoint point;
    point.x = point.y = 0;
    [backgroundImage drawAtPoint:point];

    /* 오늘 날짜를 가르키는 위치는 노란 선으로 출력 */
    CGContextBeginPath(context);
    CGContextSetLineWidth(context, 1.0);
    CGContextSetRGBStrokeColor(context, 1.0, 0.8, 0.0, 1.0);
    CGContextMoveToPoint(context, START_X + (DAY_WIDTH * ([currentDate day] - 1)), START_Y);
    CGContextAddLineToPoint(context, START_X + (DAY_WIDTH * ([currentDate day] - 1)), viewSize.height - BOTTOM_HEIGHT);
    CGContextStrokePath(context);
   
    /* 바이오리듬 출력 */
    int i, j;
    int lineX = START_X;
   
    int vcenter = START_Y + (viewSize.height - START_Y - BOTTOM_HEIGHT)/2; // 그래프의 Y 중간 좌표
   
    /* 바이오리듬 출력 */
    for (i = 1; i < 31; i++) {
        for(j = 0; j < MAX_DATATYPE; j++) {
            CGContextBeginPath(context);
            CGContextSetLineWidth(context, 2.0);
           
            CGContextSetStrokeColor(context, color[j]);
           
            CGContextMoveToPoint(context, lineX, vcenter - biorhythmData[i-1][j]);
            CGContextAddLineToPoint(context, lineX + DAY_WIDTH, vcenter - biorhythmData[i][j]);
            CGContextStrokePath(context);
        }
        lineX += DAY_WIDTH;
    }
}

- (void)dealloc {
    [backgroundImage release];
    [currentDate release];
    [super dealloc];
}

- (void)resetBiorhythmData {
    static const double s_values[MAX_DATATYPE] = {
        23.0, 33.0, 28.0 // 신체, 지성, 감성
    };
   
    /* 현재 설정된 날짜의 1일 부터 생일 사이의 날수를 구한다. */
    NSDateComponents *firstDate = [[NSDateComponents alloc] init];
    [firstDate setYear: [currentDate year]];
    [firstDate setMonth: [currentDate month]];
    [firstDate setDay:1];
   
    NSDate *tempDay = [[NSCalendar currentCalendar] dateFromComponents:firstDate];
    NSDate *birthDay = [[NSCalendar currentCalendar] dateFromComponents:birthDate];
   
    NSTimeInterval ti = [tempDay timeIntervalSinceDate:birthDay];
    [firstDate release];

    /* 바이오리듬 데이터를 구한다 */
    double days = ceil(fabs(ti) / ONEDAY_SECOND);
   
    for (int i = 0; i < 31; i++) {
        for(int j = 0; j < MAX_DATATYPE; j++) {
            biorhythmData[i][j] = sin((days/s_values[j]) * 2 * 3.14195) * 100;
        }
        days += 1.0;
    }
   
    /* 변경된 데이터로 다시 그림 */
    [self setNeedsDisplay];
}

/* 현재 날짜 변경 */
- (void)setCurrentDate:(int)year atMonth:(int)month atDay:(int)day {
    [currentDate setYear:year];
    [currentDate setMonth:month];
    [currentDate setDay:day];
}

/* 생일 변경 */
- (void)setBirthDate:(int)year atMonth:(int)month atDay:(int)day {
    [birthDate setYear:year];
    [birthDate setMonth:month];
    [birthDate setDay:day];
   
    NSLog(@"SET BIRTHDAY: %d, %d, %d", year, month, day);
}

/* 사용자가 버튼을 클릭했을 때, 날짜를 변경한다 */
- (void)changeDate:(int)pos {
    NSRange monthRange;
   
    NSTimeInterval newValue = 0;
    NSDate *tempDate = [[NSCalendar currentCalendar] dateFromComponents:currentDate];
   
    if (pos == NAV_PREVMONTH) {
        /* 이전 달로 이동을 위해 이전 달의 날수를 구한다 */
        NSDateComponents *prevMonthDate = [[NSDateComponents alloc] init];
        [prevMonthDate setYear: [currentDate year]];
        [prevMonthDate setMonth: [currentDate month]-1];
        [prevMonthDate setDay:1];
       
        monthRange = [[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit
                    inUnit:NSMonthCalendarUnit
                    forDate:[[NSCalendar currentCalendar] dateFromComponents:prevMonthDate]];
        [prevMonthDate release];
       
        /* 한달 전으로 이동 */
        newValue = ONEDAY_SECOND * monthRange.length;
        newValue = -newValue;
    }
    else if (pos == NAV_PREVDAY) {
        /* 하루 전으로 이동 */
        newValue = -ONEDAY_SECOND;
    }   
    else if (pos == NAV_NEXTDAY) {
        /* 하루 후로 이동 */
        newValue = ONEDAY_SECOND;
    }   
    else if (pos == NAV_NEXTMONTH) {
        /* 다음 달로 이동을 위해 현재 달의 날수를 구한다 */
        monthRange = [[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit
                                                        inUnit:NSMonthCalendarUnit
                                                       forDate:[[NSCalendar currentCalendar] dateFromComponents:currentDate]];
        /* 한달 후로 이동 */
        newValue = ONEDAY_SECOND * monthRange.length;
    }

    /* 날짜를 변경하고 변경된 날짜를 구한다. */
    NSDateComponents *newDate = [[NSCalendar currentCalendar] components:(NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit)
                                                            fromDate:[tempDate addTimeInterval:newValue]];
   
    /* 현재 날짜를 변경 */
    [currentDate setYear: [newDate year]];
    [currentDate setMonth: [newDate month]];
    [currentDate setDay: [newDate day]];
   
    /* 바이오리듬을 다시 계산하고 출력한다. */
    [self resetBiorhythmData];
}

- (float *)getBiorhythmDayData:(int)day {
    return biorhythmData[day-1];
}

- (NSDateComponents *)currentDate {
    return currentDate;
}
@end


3) MainView
* MainView.h
#import <UIKit/UIKit.h>

@interface MainView : UIView {
    UIImage     *barFrame[MAX_DATATYPE];
    double        bioData[MAX_DATATYPE];
}

-(void)setData:(int)value1 secondValue:(int)value2 thirdValue:(int)value2;

@end

* MainView.m
#import "Global.h"
#import "MainView.h"

@implementation MainView

- (id)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
    }
    return self;
}

- (void)awakeFromNib {
    /* 바의 배경을 위한 이미지를 로드한다. */
    for (int i = 1; i <= MAX_DATATYPE; i++) {
        barFrame[i - 1] = [[UIImage alloc] initWithContentsOfFile:
         [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"frame%d", i] ofType:@"png"]];
    }
}

- (void)drawRect:(CGRect)rect {
#define CENTER_X        210  // 바의 중간(0) 위치
#define START_Y            300  // 바가 출력될 Y 위치
#define START_X            120  // 바가 출력될 X 위치
#define BAR_HEIGHT        14.0 // 바의 높이   
#define    BAR_SPACE        40   // 각 바간 간격
   
    // Drawing code
    CGContextRef context = UIGraphicsGetCurrentContext();
   
    int y = START_Y + 15;
    CGPoint point;
   
    point.y = START_Y;
    point.x = START_X;
   
    for (int i = 0; i < MAX_DATATYPE; i++) {
        /* 배경 이미지 출력 */
        [barFrame[i] drawAtPoint:point];
       
        CGContextBeginPath(context);
        CGContextSetLineWidth(context, BAR_HEIGHT);
       
        /* 바이오리듬 값이 0보다 작으면 붉은 색으로 크면 파란색으로 표시 */
        if (bioData[i] > 0)
            CGContextSetRGBStrokeColor(context, 0.0, 0.0, 1.0, 1.0);
        else
            CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
       
        /* 바를 그린다 */
        CGContextMoveToPoint(context, CENTER_X, y);
        CGContextAddLineToPoint(context, CENTER_X + (bioData[i] * 80/100) , y);
       
        CGContextStrokePath(context);

        /* Y 좌표 변경 */
        point.y += BAR_SPACE;
        y += BAR_SPACE;
    }
}

-(void)setData:(int)value1 secondValue:(int)value2 thirdValue:(int)value3 {
    bioData[0] = value1;
    bioData[1] = value2;
    bioData[2] = value3;
}

- (void)dealloc {
    for (int i = 0; i < MAX_DATATYPE; i++) {
        [barFrame[i] release];
    }
   
    [super dealloc];
}

@end


4) MainViewController
* MainViewController.h
#import <UIKit/UIKit.h>

@class GraphView;
@class MainView;

@interface MainViewController : UIViewController {
    IBOutlet MainView        *mainView;   
    IBOutlet GraphView      *graphView;
    IBOutlet UITextField    *value_1;
    IBOutlet UITextField    *value_2;
    IBOutlet UITextField    *value_3;
   
    IBOutlet UIBarButtonItem *currentDate;
}

- (void)updateInfoUI;
- (void)birthdayChanged:(NSNotification *)note;

- (IBAction)navigationButtonClicked:(id)sender;

@end

* MainViewController.m
#import "Global.h"
#import "MainViewController.h"
#import "MainView.h"
#import "GraphView.h"

@implementation MainViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad {
    /* 오늘 날짜를 구한다. */
    NSDateComponents *today = [[NSCalendar currentCalendar]
                       components:(NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit)
                       fromDate:[NSDate date]];
   
    /* 현재 날짜 설정 */
    [graphView setCurrentDate:[today year]
                      atMonth:[today month]
                        atDay:[today day]];

    /* 생년월일 설정 */
    [graphView setBirthDate:[[NSUserDefaults standardUserDefaults] integerForKey:US_BIRTHYEAR_KEY]
                      atMonth:[[NSUserDefaults standardUserDefaults] integerForKey:US_BIRTHMONTH_KEY]
                        atDay:[[NSUserDefaults standardUserDefaults] integerForKey:US_BIRTHDAY_KEY]];

    /* 그래프를 그리고 UI를 설정한다. */
    [graphView resetBiorhythmData];
    [self updateInfoUI];
   
    /* 환경설정에서 생일이 변경되었을 때를 위해 옵저버로 등록 */
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(birthdayChanged:)
                                                 name:NM_BIRTHDAYCHANGED
                                               object:nil];
}

- (void)updateInfoUI {
    /* 하단 타이틀에 현재 날짜를 출력 */
    NSDateComponents *date = [graphView currentDate];
    [currentDate setTitle:[NSString stringWithFormat:@"%d.%02d.%02d",
                           [date year], [date month], [date day]]];
   
    float *bioValue = [graphView getBiorhythmDayData:[date day]];
    int value1 = (int)ceil(bioValue[0]);
    int value2 = (int)ceil(bioValue[1]);
    int value3 = (int)ceil(bioValue[2]);
   
    /* 각 바이오리듬 값 출력 */
    [value_1 setText:[NSString stringWithFormat:@"%d", value1]];
    [value_2 setText:[NSString stringWithFormat:@"%d", value2]];
    [value_3 setText:[NSString stringWithFormat:@"%d", value3]];
   
    /* mainView에 현재 설정된 값을 알려주고, 바가 다시 그려지도록 한다. */
    [mainView setData:value1 secondValue:value2 thirdValue:value3];
    [mainView setNeedsDisplay];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
    // Release anything that's not essential, such as cached data
}

- (void)dealloc {
    [super dealloc];
}

- (void)birthdayChanged:(NSNotification *)note
{
    /* 생일이 변경되었을 때 다시 설정하고 그려지도록 한다. */
    [graphView setBirthDate:[[NSUserDefaults standardUserDefaults] integerForKey:US_BIRTHYEAR_KEY]
                      atMonth:[[NSUserDefaults standardUserDefaults] integerForKey:US_BIRTHMONTH_KEY]
                        atDay:[[NSUserDefaults standardUserDefaults] integerForKey:US_BIRTHDAY_KEY]];
   
    [graphView resetBiorhythmData];
    [self updateInfoUI];
}       

- (IBAction) navigationButtonClicked:(id)sender {
    /* 사용자가 날짜 이동 버튼을 클릭하였을 경우 처리 */
    [graphView changeDate:[sender tag]];
    [self updateInfoUI];
}

@end


5) FlipsideViewController
* FlipsideViewController.h
#import <UIKit/UIKit.h>

@interface FlipsideViewController : UIViewController {
    IBOutlet UIDatePicker    *datePicker;
}

@property (nonatomic, retain) UIDatePicker *datePicker;

@end

* FlipsideViewController.m
#import "FlipsideViewController.h"

@implementation FlipsideViewController

@synthesize datePicker;

- (void)viewDidLoad {
    self.view.backgroundColor = [UIColor viewFlipsideBackgroundColor];       
 }

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
    // Release anything that's not essential, such as cached data
}

- (void)dealloc {
    [super dealloc];
}

@end


5) RootViewController
* RootViewController.m
#import "Global.h"
#import "RootViewController.h"
#import "MainViewController.h"
#import "FlipsideViewController.h"

@implementation RootViewController

@synthesize infoButton;
@synthesize flipsideNavigationBar;
@synthesize mainViewController;
@synthesize flipsideViewController;

- (void)viewDidLoad {
   
    MainViewController *viewController = [[MainViewController alloc] initWithNibName:@"MainView" bundle:nil];
    self.mainViewController = viewController;
    [viewController release];
   
    [self.view insertSubview:mainViewController.view belowSubview:infoButton];
}

- (void)loadFlipsideViewController {
   
    FlipsideViewController *viewController = [[FlipsideViewController alloc] initWithNibName:@"FlipsideView" bundle:nil];
    self.flipsideViewController = viewController;
    [viewController release];
   
    // Set up the navigation bar
   
    UINavigationBar *aNavigationBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 44.0)];
    aNavigationBar.barStyle = UIBarStyleBlackOpaque;
    self.flipsideNavigationBar = aNavigationBar;
    [aNavigationBar release];
   
    UIBarButtonItem *buttonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(toggleView)];
    UINavigationItem *navigationItem = [[UINavigationItem alloc] initWithTitle:@"iBiorhythm"];
    navigationItem.rightBarButtonItem = buttonItem;
    [flipsideNavigationBar pushNavigationItem:navigationItem animated:NO];
    [navigationItem release];
    [buttonItem release];
}

- (IBAction)toggleView {   
    if (flipsideViewController == nil) {
        [self loadFlipsideViewController];
    }
   
    UIView *mainView = mainViewController.view;
    UIView *flipsideView = flipsideViewController.view;
   
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:1];
    [UIView setAnimationTransition:([mainView superview] ? UIViewAnimationTransitionFlipFromRight : UIViewAnimationTransitionFlipFromLeft) forView:self.view cache:YES];
   
    if ([mainView superview] != nil) {
        [flipsideViewController viewWillAppear:YES];
        [mainViewController viewWillDisappear:YES];
        [mainView removeFromSuperview];
        [infoButton removeFromSuperview];
        [self.view addSubview:flipsideView];
        [self.view insertSubview:flipsideNavigationBar aboveSubview:flipsideView];
        [mainViewController viewDidDisappear:YES];
        [flipsideViewController viewDidAppear:YES];
       
        /* DataPicker 날짜를 저장된 날짜로 설정 (현재 동작하지 않음) */
        NSDateComponents *curDate = [[NSDateComponents alloc] init];
       
        int year = [[NSUserDefaults standardUserDefaults] integerForKey:@"birth_year"];
        int month = [[NSUserDefaults standardUserDefaults] integerForKey:@"birth_year"];
        int day = [[NSUserDefaults standardUserDefaults] integerForKey:@"birth_year"];

        [curDate setYear: year];
        [curDate setMonth: month];
        [curDate setDay: day];
   
        NSDate *tempDate = [[NSCalendar currentCalendar] dateFromComponents:curDate];
        [[flipsideViewController datePicker] setDate:tempDate animated:YES];
           
        [curDate release];
    } else {
        [mainViewController viewWillAppear:YES];
        [flipsideViewController viewWillDisappear:YES];
        [flipsideView removeFromSuperview];
        [flipsideNavigationBar removeFromSuperview];
        [self.view addSubview:mainView];
        [self.view insertSubview:infoButton aboveSubview:mainViewController.view];
        [flipsideViewController viewDidDisappear:YES];
        [mainViewController viewDidAppear:YES];
       
        /* 사용자가 설정한 날짜(생일)를 저장 한다 */
        NSDateComponents *newDate = [[NSCalendar currentCalendar]
              components:(NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit)
              fromDate:[[flipsideViewController datePicker] date]];
       
        [[NSUserDefaults standardUserDefaults] setInteger:[newDate year] forKey:US_BIRTHYEAR_KEY];
        [[NSUserDefaults standardUserDefaults] setInteger:[newDate month] forKey:US_BIRTHMONTH_KEY];
        [[NSUserDefaults standardUserDefaults] setInteger:[newDate day] forKey:US_BIRTHDAY_KEY];
       
        /* 바이오리듬이 변경되도록 메시지를 보낸다. */
        [[NSNotificationCenter defaultCenter]
                   postNotificationName:NM_BIRTHDAYCHANGED
                   object:self];
    }
    [UIView commitAnimations];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
    // Release anything that's not essential, such as cached data
}

- (void)dealloc {
    [infoButton release];
    [flipsideNavigationBar release];
    [mainViewController release];
    [flipsideViewController release];
    [super dealloc];
}

@end

다음 포스팅에선 인터페이스 빌더에서 작업을 하고 어플리케이션이 동작하도록 완성시켜 보겠습니다. 동작은 하는데 제대로 만든 것인지는 모르겠습니다.

간단하게 아이폰용 바이오리듬 어플리케이션을 만들어 보겠습니다. 저도 처음 아이폰 SDK를 사용하여 만들어 보았기 때문에, 과정을 가능한 상세하게 설명할려고 합니다. 바이오리듬은 이전에 데쉬보드 위젯에서의 방식을 사용 하였습니다. 역시나 제대로 된 방법인지는 잘 모르겠습니다.




1. 프로젝트 생성
Xcode를 실행하여 파일 메뉴에서 New Project를 클릭합니다. iPhone OS의 Application 항목에서 가장 마지막에 있는 'Window-Based Application'을 선택한 후 Choose... 버튼을 클릭합니다.

프로젝트명을 'iBio'로 입력하고 Save 버튼을 클릭합니다.


2. iBioView
1) 클래스생성
바이오리듬을 막대그래프 형식으로 보여줄 View 클래스를 만들어 보겠습니다. 메뉴에서 파일/New File...(또는 단축키: ⌘+N)을 클릭합니다. IPhone OS/Cocoa Touch Classes를 클릭하고 아래와 같이 UIView subclass를 선택한 다음 Next 버튼을 클릭합니다.


다음 창에서 아래와 같이 File Name에 iBioView.m을 입력한 후에 Finish 버튼을 클릭합니다.

2) iBioView.h
iBioView.h 파일에 아래와 같이 내용을 추가 합니다.
#import <UIKit/UIKit.h>

#define MAX_DATATYPE        3

@interface iBioView : UIView {
   double bioData[MAX_DATATYPE];
}

- (void)showBioData: (double)days;
- (int)getBioDataAt: (int)index;

@end

MAX_DATATYPE은 바이오리듬 항목을 의미하며, 신체/지성/감성 등 3개의 항목을 가지고 있습니다. bioData에는 각 항목별로 오늘의 바이오리듬 값이 저장됩니다.

3) iBioView.m
iBioView.m 파일에 아래와 같이 내용을 추가 합니다. 설명은 소스내의 간단한 주석으로 대신하겠습니다.
#import "iBioView.h"

@implementation iBioView

- (id)initWithFrame:(CGRect)frame {
   if (self = [super initWithFrame:frame]) {
          /* 바이오리듬 값을 0으로 초기화 */

           for (int i = 0; i < MAX_DATATYPE; i++) {
               bioData[i] = 0.0;

       }
   }
   return self;
}

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
   
   /* 세개의 바이오리듬 값 막대 출력 */
    for (int i = 0; i < MAX_DATATYPE; i++) {
        CGContextBeginPath(context);
        CGContextSetLineWidth(context, 15.0);
       
        int y = 34 + (i * 40);
      
       /* 바이오리듬 값이 0보다 작으면 붉은 색으로 크면 파란색으로 표시 */
        if (bioData[i] > 0)
            CGContextSetRGBStrokeColor(context, 0.0, 0.0, 1.0, 1.0);
        else
            CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
      
       /* 선을 그린다 */
        CGContextMoveToPoint(context, 200, y);
        CGContextAddLineToPoint(context, 200 + (bioData[i] * 80/100) , y);
       
        CGContextStrokePath(context);
    }
}

- (void)dealloc {
   [super dealloc];
}

- (void)showBioData: (double)days {
    static const double s_values[MAX_DATATYPE] = {
        23.0, 28.0, 33.0
    };
   
   /* 각 바이오리듬 설정 */
    for (int i = 0; i < MAX_DATATYPE; i++) {
        bioData[i] = sin((days/s_values[i]) * 2 * 3.14195) * 100;
    }
   
   /* 변경된 값으로 view가 다시 그려지도록 한다 */
    [self setNeedsDisplay];
   
}

- (int)getBioDataAt: (int)index {
    return (int)bioData[index];
}

4) 프레임 워크 추가
CGContextBeginPath와 같이 코어그래픽스 프레임워크의 모듈을 사용하기 위해 해당 프레임워크를 추가해야 합니다. 아래와 같이 Xcode 좌측의 Frameworks에서 마우스를 우클릭하여 Add/Existing Frameworks... 메뉴를 선택합니다.


선택창이 열리면 /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/System/Library/Frameworks  디렉토리에서 /CoreGraphics.framework를 선택합니다.

* 확인
완료되면 좌측과 같이 CoreGraphics.framework가 추가되어 있는 것을 확인할 수 있습니다.




3. iBioAppDelegate 변경
1) iBioAppDelegate.h
iBioAppDelegate.h 파일에 아래의 내용을 추가합니다. 추가된 항목은 인터페이스 빌더에서 각각의 오브젝트와 액션으로 연결됩니다.

#import <UIKit/UIKit.h>

@class iBioViewController;
@class iBioView;

@interface iBioAppDelegate : NSObject <UIApplicationDelegate> {
   IBOutlet UIWindow *window;

    IBOutlet iBioView *view;
    IBOutlet UIDatePicker *datePicker;
   
    IBOutlet UITextField *text_1;
    IBOutlet UITextField *text_2;
    IBOutlet UITextField *text_3;
}

@property (nonatomic, retain) UIWindow *window;

- (IBAction) viewButtonClicked:(id)sender;

@end


2) iBioAppDelegate.m
iBioAppDelegate.m 파일에 아래의 내용을 추가합니다.
#import "iBioAppDelegate.h"
#import "iBioView.h"

@implementation iBioAppDelegate

@synthesize window;

- (void)applicationDidFinishLaunching:(UIApplication *)application {   
   
    // Override point for customization after app launch   
    [window makeKeyAndVisible];
}


- (void)dealloc {
    [window release];
    [super dealloc];
}

/* 사용자가 보기 버튼을 클릭시에 메시지를 받는 메소드 */
- (IBAction)viewButtonClicked:(id)sender {
    /* 사용자가 DatePicker에서 입력한 생일과 현재 날짜로 부터 차이를 구함 */
    NSTimeInterval ti = [[datePicker date] timeIntervalSinceNow];
    double days = ceil(fabs(ti) / (24 * 60 * 60));
   
   /* view에서 days를 기준으로 바이오리듬을 구하고 출력되도록 한다 */
    [view showBioData: days];
   
   /* 각 텍스트필드에 새로 계산된 바이오리듬 값으로 설정 */ 
    [text_1 setText: [NSString stringWithFormat: @"%d", [view getBioDataAt:0]]];
    [text_2 setText: [NSString stringWithFormat: @"%d", [view getBioDataAt:1]]];
    [text_3 setText: [NSString stringWithFormat: @"%d", [view getBioDataAt:2]]];
}

@end

* 인터페이스 빌더 오픈
변경된 모든 파일들을 저장하고 좌측과 같이 MainWindow.xib를 더블클릭하여 인터페이스 빌더를 실행합니다.



4. 사용자 인터페이스 생성
1) DatePicker
* Library 윈도우
사용자가 생일을 입력할 수 있도록 DatePicker를 설정합니다.


위와 같이 라이브러리 윈도우의 Cocoa Touch Plugin/Data Views에서 Date Picker를 클릭한 후에 드래그 하여 윈도우에 가져다 놓습니다. 아래가 윈도우에 위치한 모습니다.


* 속성 변경
위의 윈도우에서 DatePicker가 선택된 상태에서 속성창에서 좌측과 같이 설정합니다.

속성창이 안보이면 선택된 상태에서  단축키(⌘+1)를 이용합니다.










2) ToolBar
다시 라이브러리 윈도우의 Windows, Views & Bars 항목에서 좌측과 같은 Toolbar 아이콘을 드래그 하여 윈도우의 하단에 아래와 같이 배치합니다.



* 타이틀 변경
툴바의 Item 버튼을 더플클릭하면 좌측과 같이 입력 가능한 상태로 변경됩니다. '보기'라고 입력합니다.



3) 안내문구
다시 라이브러리 윈도우의 Inputs & Values 항목에서 Label을 윈도우의 DatePicker 위로 드래그 해서 놓습니다.


* 속성 변경
좌측과 같이 속성창에서 Text에  "생일을 선택한 후 보기를 클릭하세요" 라고 입력합니다.

하단의 Layout에서 정렬을 중앙 정렬로 놓습니다.






* 확인
현재까지 윈도우의 모습은 아래와 같습니다.
사용자 삽입 이미지


4) View
다시 라이브러리 윈도우의 Windows, Views & Bars 항목에서 좌측과 같은 View 아이콘을 드래그 하여 크기를 조절하여 윈도우의 상단에 아래와 같이 배치합니다.
* 배경 색상 변경
속성창의 Background의 색상선택 버튼을 클릭하여 좌측과 같이 검정색으로 설정합니다.








* 클래스 변경
Class에 Xcode에서 만들어 두었던 iBioView를 선택합니다.





5) 제목, 텍스트 필드
* 제목 라벨
라이브러리 윈도우에서 Label을 세번 드래그 해서 좌측과 같이 배치합니다. 

라벨을 더블클릭하여 입력모드가 되면 각각 '신체:', '감성:', '지성:'으로 입력합니다.










* 텍스트 필드
라이브러리 윈도우에서 좌측과 같은 TextFiled도 똑같이 세번 드래그 해서 이전에 배치한 라벨의 옆에 아래와 같이 배치합니다.



* 속성 변경
⌘를 누른 상태에서 마우스로 클릭하여 좌측과 같이 세개의 텍스트 필드를 선택합니다. ⌘+1로 속성창을 엽니다.







사용자로 부터 입력에 반응하지 않기 위해 'User Interaction Eanbled'를 체크를 해제합니다.



5. 연결
MainWindow.xib 윈도우에서 I Bio App Delegate를 마우스로 우클릭합니다. 아래와 같이 iBioAppDelegate.h에서 생성해 놓은 Outlet들과 'viewButtonCliecked' Action이 있습니다. 이제 실제 오브젝트들과 연결해 보겠습니다.


1) Date Picker 연결
dataPicker 우측의 원 모양의 아이콘을 클릭하면 좌측과 같이 +로 모양이 변경됩니다. 이 상태에서 마우스 버튼을 클릭한 채로 아래와 같이 윈도우의 DatePicker에 드래그해서 놓습니다.


* 확인
완료되면 좌측과 같이 연결된 오브젝트가 표시되며, 우측의 원 모양 아이콘이 on으로 표시되어 연결되어 있슴을 알려 줍니다. x 모양의 아이콘을 클릭하면 연결이 해제됩니다.

2) TextFiled 연결
위와 같은 방법으로 아래와 같이 TextField를 text_1, text_2, text3과 위에서 부터 순서대로 연결합니다.

3) View 연결
같은 방법으로 아래와 같이 view도 연결합니다.

4) viewButtonClicked 메소드 연결
사용자가 보기 버튼을 클릭하면 viewButtonClicked가 실행되도록 위와 같은 방법으로 viewButtonClicked를 툴바의 보기 버튼과 연결합니다.

5) 연결 확인

좌측과 같이 모든 항목들이 정확하게 연결이 되어 있는 것을 확인합니다.

이제 모두 완료되었습니다. 저장 후에 빌드를 한후 실행하여 동작을 확인해 봅니다.









이상 간단하게 첫 아이폰 어플리케이션을 만들어 보았습니다. DatePicker도 동작과 설정이 조금 이상한 것 같고, 처음 갑작스레 만들어 본 것이라 맞는 방법인지 의심스럽습니다. 혹시 잘못된 부분이 있으면 댓글로 알려 주시면 감사하겠습니다.

기본 UI들이 멋있어서 맞출려면 디자인이나 이미지에 신경을 써야 할 것 같습니다. 나중에 조금 더 알아본 후에 월별로 출력하도록 수정하고 몇가지 변경해 본 후에 다시 한번 올려 보겠습니다.