이번에는 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
모든 댓글을 환영합니다. (욕설과 광고는 삭제합니다.)
  1. 달룟 2008.10.06 01:46  댓글주소  수정/삭제  댓글쓰기

    dataq는 오타지요? 설명 대로 따라하니까 쉽네요.

  2. Favicon of http://sukwoo.blogspot.com BlogIcon 장림 2008.10.08 16:32  댓글주소  수정/삭제  댓글쓰기

    실행하면 Stop Executable 발생합니다.
    BookList
    Project:"BookList.xcodeproj" Target:"BookList"

    그런데 프로그램은 정상적으로 동작하는군요.

    • Favicon of https://www.cocoadev.co.kr BlogIcon cocoadev 2008.10.08 17:20 신고  댓글주소  수정/삭제

      아.. 그런가요? 저는 그런 로그를 못 보았습니다. 제가 작업한 파일을 올려보았습니다. 혹시 뭔가 잘 못되었는지 잘 모르겠네요. ^^;;

  3. Favicon of http://sukwoo.blogspot.com BlogIcon 장림 2008.10.08 20:03  댓글주소  수정/삭제  댓글쓰기

    올려주신 파일은 잘 동작합니다.
    제가 잘못했나봅니다. 감사합니다.

  4. ttkaka 2010.01.09 23:06  댓글주소  수정/삭제  댓글쓰기

    core data를 찾아보다가 이곳까지 왔네요. 잘봤습니다.

    위의 예제를 보니 core data를 미리 만들수 있겠군요.
    그런데 위의 예제에서 입력해서 만든 데이터 파일을 어디에 어떤파일로 저장되는지요.
    그 파일을 따로 저장해서 다른 어플에서 읽어오게 하려고 하는데 가능할지 모르겠네요.
    sqlite같은 경우 데이터를 만들 수 있는 도구가 있던데 core data는 없나보죠.

    • Favicon of https://www.cocoadev.co.kr BlogIcon cocoadev 2010.01.11 16:06 신고  댓글주소  수정/삭제

      데이터 파일은 사용자가 저장 다이알로그박스에서 지정된 폴더와 이름으로 저장됩니다. 어플리케이션간에 공유는 가능할 것 같습니다. 위의 방법보다는 직접 코드를 생성하여 만드시는게 더 편할 것 같고요. 저도 잘 몰라서 명확한 답변을 드릴 수가 없어 죄송합니다.

  5. iamwhatiam 2010.10.07 09:40  댓글주소  수정/삭제  댓글쓰기

    10.6에서는 다소 바뀐 부분이 있어서 첫 시작부터 헤깔리긴 했지만... 덕분에 잘 배웠습니다.
    다음번에는 혹시... MySql이나... Oracle에 연동되는 Data관련 강좌를 부탁드려도 될까요?



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
모든 댓글을 환영합니다. (욕설과 광고는 삭제합니다.)
  1. Favicon of http://mytrue.net BlogIcon 트루 2008.09.26 18:18  댓글주소  수정/삭제  댓글쓰기

    Xcode처음 해보는데 위에 설명대로 만들어 보니 잘 되네요~ =ㅇ=
    재밌습니다.. ㅎㅎ;; 근데 버튼에 이미지는 템플릿이 이미 정의되어 있는걸 불러다 쓰는건가요?;;

    • Favicon of https://www.cocoadev.co.kr BlogIcon cocoadev 2008.09.26 20:38 신고  댓글주소  수정/삭제

      넵. 시스템에서 공유해서 사용하는 이미지를 불러 오는 것입니다. 인터페이스빌더 라이브러리 창에서 Media 탭의 Library/System Media에 있습니다.

  2. 좌절직전 2008.10.09 18:01  댓글주소  수정/삭제  댓글쓰기

    올려주신 데로 착실히 따라가고 있는 중입니다.
    염치없지만 도움청합니다.
    변수명만 바꿔서 돌려보는데 에러가 나는데...... 왜 문법 오류가 나는지 모르겠습니다.
    소스말고...다른부분에서 원인을 찾아야 되는건지..
    도와 주시면 은혜를 잊지 않겠습니다. ㅜ.ㅜ

    //선언부
    IBOutlet NSTextField *Label;
    NSPoint Point;


    //- (void)awakeFromNib 구현부
    Point = [Label frame].origin;

    //에러
    error:syntax error before '=' token

  3. 탈좌절 2008.10.10 09:57  댓글주소  수정/삭제  댓글쓰기

    답변을 정말 빨리해주셨군요.
    감사 합니다.
    아무래도 꽁(?)으로 습득해 볼려는 의도는 접어야 겠습니다.
    책을 꼭 봐야겠습니다.
    수고하세요. ^____^

    • Favicon of https://www.cocoadev.co.kr BlogIcon cocoadev 2008.10.10 11:13 신고  댓글주소  수정/삭제

      개발환경을 둘러 보거나 잠시 사용해 볼 것이 아니면, 아무래도 찬찬히 책 한번 보시는게 좋겠죠. 탈좌절님도 수고하세요. :)

  4. Favicon of http://inthewhite.net BlogIcon july.fool 2008.10.13 02:07  댓글주소  수정/삭제  댓글쓰기

    오오 +_ +
    정말 꼼꼼한 튜토리얼 잘 보겠습니다~
    이제막 xcode3 시작하려하는데 엄청난 도움이 되네요 :)

  5. 맥열공 2008.12.30 16:06  댓글주소  수정/삭제  댓글쓰기

    친절한 내용 정리 너무 감사 합니다.
    저같은 초보에게 너무나 큰 도움이 되고 있습니다.

  6. unik 2009.01.12 23:26  댓글주소  수정/삭제  댓글쓰기

    interface builder 에서 write class 를 안하고 직접 다 쳐넣는 이유가 특별히 있는건가요..?

  7. Favicon of http://www.themuser.net BlogIcon The+Muser 2009.04.21 07:41  댓글주소  수정/삭제  댓글쓰기

    아..정말 굉장합니다!! +_+
    이제야 이런곳을 발견하다니..자주 들러서 열공하겠습니다~~~

    [덧] 혹시 추천해주실만한 책 같은 것 있나요?

    • Favicon of https://www.cocoadev.co.kr BlogIcon cocoadev 2009.04.23 13:41 신고  댓글주소  수정/삭제

      번역되어 나온 책이 코코아 프로그래밍이란 책과 아이폰 쿡북 두권밖에 없습니다. 처음 공부하신다면 코코아 프로그래밍이란 책이 좋을 것 같습니다. :)

  8. Munggu 2009.06.29 15:46  댓글주소  수정/삭제  댓글쓰기

    감사합니다 많은 도움이 되었어요

  9. 지나가다 2010.01.23 21:31  댓글주소  수정/삭제  댓글쓰기

    xcode로 처음 해 본 맥 플그램이네요. 재미있게 잘 보고 갑니다 ^^;



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

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



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

모든 댓글을 환영합니다. (욕설과 광고는 삭제합니다.)
  1. 함지 2008.09.11 13:56  댓글주소  수정/삭제  댓글쓰기

    벌레보고 :
    1. 처음 실행될 때는 제대로 된 값이 뜹니다만, 재실행 시부터 i창도 그렇고 결과창에도 알 수 없는 값들이 들어오는거 같습니다.
    2. 버튼의 좌이동값과 우이동값이 제대로 먹히지 않는거 같구요.

    3. 색감과 아이콘을 좀더 화장을 시키고 헬프파일에 좀 멋진 말 넣은 다음, 한 5불 받고 앱스토어에 올려서 뿌려버리세요 !!

    • Favicon of https://www.cocoadev.co.kr BlogIcon cocoadev 2008.09.11 14:49 신고  댓글주소  수정/삭제

      확인해 보니 GraphView.m 파일의 159번째 줄에 주석을 막아 놓은 '/'가 지워져 있었습니다. ^^;; 이전 포스팅에서도 수정하고 소스도 새로 올렸습니다. DatePicker 문제는 본문에서 언급을 했는데, 아직 해결책을 못 찾았습니다.

      알려 주셔서 감사합니다. :)

    • 버들피리 2009.03.30 03:42  댓글주소  수정/삭제

      break point를 잡아보니 DatePicker 로 데이타를 넘기기전에 값이 벌써 이상한데요.. 생일 초기값 설정을 어디서 하는지요..

  2. 함지 2008.09.11 22:47  댓글주소  수정/삭제  댓글쓰기

    와, 볼수록 환상이네요 ! 5불은 이것저것 빼고, 뜯기는거 빼면 남는게 없겠고, 10불이면 시장 있겠슴다. 아, 근데, 말씀드리기 좀 그런데,,, 칼라는 도스시절 칼라 버리시고, 애플감각의 칼라(즉, 헨슨이 텍스트메이트서 주로 쓰는 칼라 되겠지요)로 발라주시면 훨~씬 잘 먹힐거 같어요... 한국에서야 태극기 색깔, 하늘색, 분홍색이 KBS가 조사한 대한민국 국민색지만서두, 애플의 뽀대하고는 참, 물과 기름 내지는 양복에 갓쓴 듯한 감을 솔직히 지우기가 어렵거든요. 저만 그런가...

    • Favicon of https://www.cocoadev.co.kr BlogIcon cocoadev 2008.09.12 13:59 신고  댓글주소  수정/삭제

      디자인은 제가 봐도 좀 그렇지만 튜토리얼 용도로 만든 것이니 그다지 신경쓰지 않았습니다. 애플 App 스토어에는 1센트에 올려도 안팔릴 것 같은데요. 하기 별에 별 사람들이 다 있으니 한두개는 팔릴지 모르겠습니다. ^^;;

      아무튼 좋게 봐주시니 감사합니다. :)

  3. 버들피리 2009.03.29 16:59  댓글주소  수정/삭제  댓글쓰기

    MainWindow.xib 에서 아이콘이 어디있나 했더니.. 배경색을 검은색으로 바꾸니 보이네요. ^^
    너무나 자세한 설명 고맙습니다. 포스팅하느라 힘드셨겠어요..

  4. Favicon of http://tohappy.tistory.com BlogIcon tohappy 2009.06.14 22:26  댓글주소  수정/삭제  댓글쓰기

    한 참 고생하다가 여기 오면 Hint 를 얻고 갑니다.
    그리고 정리의 달인 이십니다. 항상 좋은 글 잘 보고 있습니다.

    • Favicon of https://www.cocoadev.co.kr BlogIcon cocoadev 2009.06.15 16:18 신고  댓글주소  수정/삭제

      카테고리랑 글들이 잘 정리가 안되어 있는 것 같아 늘 한번 정리를 해야지 하고 마음은 먹고 있습니다. 그리고 실생활에서는 정리를 전혀 못합니다. ^^; 좋은 말씀 감사합니다. :)

  5. 씨커 2009.06.24 15:56  댓글주소  수정/삭제  댓글쓰기

    좋은 자료 공개해 주셔서 감사합니다. ^^
    근데... 생일 변경하는 버튼이 잘 안눌리는데, 수정이 필요하겠네요.

  6. 씨커 2009.06.25 12:52  댓글주소  수정/삭제  댓글쓰기

    RootViewController.m 파일에 버그(? 라고 하기도 뭐한... ^^)가 있어서 DataPicker 초기값 설정이 제대로 안되네요.

    수정전 :
    int year = [[NSUserDefaults standardUserDefaults] integerForKey:@"birth_year"];
    int month = [[NSUserDefaults standardUserDefaults] integerForKey:@"birth_year"];
    int day = [[NSUserDefaults standardUserDefaults] integerForKey:@"birth_year"];

    수정후 :
    int year = [[NSUserDefaults standardUserDefaults] integerForKey:@"birth_year"];
    int month = [[NSUserDefaults standardUserDefaults] integerForKey:@"birth_month"];
    int day = [[NSUserDefaults standardUserDefaults] integerForKey:@"birth_day"];

  7. Favicon of https://www.cocoadev.co.kr BlogIcon cocoadev 2009.06.25 13:51 신고  댓글주소  수정/삭제  댓글쓰기

    아.. 오류가 있나 보네요. 알려 주셔서 감사합니다. :) 코딩을 주로 Copy&Paste에 의지하다보니... ^^;

  8. 아키찰스 2010.10.11 16:48  댓글주소  수정/삭제  댓글쓰기

    안녕하세요~^^
    맥부기를 통해서 블로그를 알게되었습니다.
    덕분에 많은 가르침과 큰 도움 받아서 정말 감사합니다 ^^

    그리고 질문이 있습니다 ^^;

    1) GraphView.m 에서 addTimeInterval 부분에서 "addTimeInterval" is deprecated 라는 경고가 뜨던데 dateByAddingTimeInterval 로 바꾸니 에러는 멈췄습니다. 이렇게 해도 상관이 없을까요? ㅎ

    2) 생일을 변경해도 바이오 리듬값이 똑같아서요.
    GraphView.m 에서
    -(void)setBirthDate: (int)year atMonth: (int)month atDay: (int)day 에
    [brthDate setYear:year];
    [brthDate setMonth:month];
    [brthDate setDay:day];
    이 부분에 [birthDate year], [birthDate month], [birthDate day]를 출력해 보니 계속 0 이나 와서요~

    혹시 시간나시면 조언 좀 부탁드리겠습니다.

    그리고 다시 한번 멋진 자료들을 포스팅해서 공유해 주신점 진심으로 감사드립니다.



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

  • << : 한달 전으로 이동
  • < : 하루 전으로 이동
  • > : 하루 후로 이동
  • >> : 한달 후로 이동
  • 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

다음 포스팅에선 인터페이스 빌더에서 작업을 하고 어플리케이션이 동작하도록 완성시켜 보겠습니다. 동작은 하는데 제대로 만든 것인지는 모르겠습니다.
모든 댓글을 환영합니다. (욕설과 광고는 삭제합니다.)
  1. 함지 2008.09.09 18:34  댓글주소  수정/삭제  댓글쓰기

    으악 ~~~ 혹시, 어느 별에서 오셨는지요

  2. Favicon of http://www.juniac.net BlogIcon juniac 2008.09.10 13:24  댓글주소  수정/삭제  댓글쓰기

    잘봤습니다 ^^

  3. 이승환 2008.11.06 14:32  댓글주소  수정/삭제  댓글쓰기

    좋은 정보 감사합니다
    따라하면서 공부하고 있는데
    RootViewController.h는 수정 필요 없는지요

  4. 황은영 2009.04.01 20:36  댓글주소  수정/삭제  댓글쓰기

    5) RootViewController
    * RootViewController.m
    #import "Global.h"
    #import "RootViewController.h"
    #import "MainViewController.h"
    #import "FlipsideViewController.h"
    /*
    #import "MainView.h"
    그래서 헤더파일 MainView.h를 추가햇더니 에러가 안났어요.><
    */
    제가 한게 맞은건지 확인부탁드려요.ㅎㅎ

    • Favicon of https://www.cocoadev.co.kr BlogIcon cocoadev 2009.04.03 17:25 신고  댓글주소  수정/삭제

      갑자기 '그래서'가 나오니 당황되네요. ^^; MainView 클래스를 따로 사용하는 부분이 없기 때문에 헤더파일을 추가하지 않으셔도 될 것 같습니다.



간단하게 아이폰용 바이오리듬 어플리케이션을 만들어 보겠습니다. 저도 처음 아이폰 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들이 멋있어서 맞출려면 디자인이나 이미지에 신경을 써야 할 것 같습니다. 나중에 조금 더 알아본 후에 월별로 출력하도록 수정하고 몇가지 변경해 본 후에 다시 한번 올려 보겠습니다.
모든 댓글을 환영합니다. (욕설과 광고는 삭제합니다.)
  1. 달룟 2008.09.04 19:24  댓글주소  수정/삭제  댓글쓰기

    와! 멋진데요! 저도 해 볼께요.(가능할까?ㅋ)

  2. Favicon of http://me2day.net/wookay BlogIcon ㄴㅇㄱ 2008.09.04 20:05  댓글주소  수정/삭제  댓글쓰기

    고맙습니다~~~

  3. 달룟 2008.09.04 20:42  댓글주소  수정/삭제  댓글쓰기

    "4) 프레임 워크 추가"할 때 이런 게 뜨는데 정상인가요?

    http://screencast.com/t/8RfrobvM

  4. 달룟 2008.09.04 21:13  댓글주소  수정/삭제  댓글쓰기

    똑같지는 않지만, 거의 같게 만들었습니다.

  5. 함지 2008.09.05 16:08  댓글주소  수정/삭제  댓글쓰기

    브라보 ! 멋지네요. 역시 개발이력(짬빱?!)이 되시는 분들 진도 나가시는게 대단하네요. 달력 돌아가는게 예술입니다 !

    • Favicon of https://www.cocoadev.co.kr BlogIcon cocoadev 2008.09.05 18:28 신고  댓글주소  수정/삭제

      날짜 선택하는 게 하도 커서 뭐가 있어 보이는데, 진도 나간 건 별로 없습니다. ^^;;

      아이폰 개발은 별로 관심이 없었는데, 말씀하신 달력의 예술적인 움직임에 반해서 한번 사용해 보았습니다. :)

  6. Favicon of http://rococo.tistory.com BlogIcon B군 2008.09.09 00:11  댓글주소  수정/삭제  댓글쓰기

    차근차근 잘 설명을 해주셔서 따라하기가 넘 쉬웠어요^-^

    • Favicon of https://www.cocoadev.co.kr BlogIcon cocoadev 2008.09.09 11:54 신고  댓글주소  수정/삭제

      감사합니다. 두번째 버젼은 만들어 놓고 포스팅할 엄두를 못내고 있어는데, B군님의 댓글에 힘을 내서 오늘 점심먹고 시작해 보아야 겠네요. ^^

  7. 함지 2008.09.09 14:29  댓글주소  수정/삭제  댓글쓰기

    이제 사인웨이브가 한,, 일주일, 열흘, 한달치가 색깔별로 떠주면 완전한 App 하나 완성인가요 !? 안그래도 오늘 머니타임즈인가에 KTF의 iPhone 계약건이 나왔던데 론칭기념으로 하나 날려주세요 !

    • Favicon of https://www.cocoadev.co.kr BlogIcon cocoadev 2008.09.09 16:24 신고  댓글주소  수정/삭제

      한달 단위로 보여 주며 하단에 일별로 상세하게 볼 수 있도록 하였습니다. 곧 올리겠습니다.

      기쁜 소식이 나왔네요. 알려 주셔서 감사합니다. ^^

  8. felix 2008.11.03 19:38  댓글주소  수정/삭제  댓글쓰기

    맥북 지르고 ㅋㅋ SDK 깔아 본후 ㅋ

    바로 시작해서 따라 해봤습니다. ㅋ

    중간중간에 에러 나고 잘 안되는 부분이 있긴 했는데

    이제 잘됩니다. ^^;; ㅋ 이제 Toolchain은 그만해야 겠습니다. ^^ ㅋㅋ

  9. skna 2008.11.07 14:53  댓글주소  수정/삭제  댓글쓰기

    결국 자기 디바이스에 올리려면 developer 로 등록해야 되나요?

  10. Favicon of https://cre8ive.tistory.com BlogIcon cre8ive 2008.11.09 02:01 신고  댓글주소  수정/삭제  댓글쓰기

    정말 유익하게, 즐겁게 보면서 따라했습니다.
    조금이나마 Cocoa Touch 에 대한 감을 잡는데 큰 도움이 되었습니다.

    감사합니다 ^^

    IDP 신청화면을 들어갔더니 접수번호알려주고
    기다리라는 화면이 나오네요. 얼마나걸릴지
    빨리 iPod Touch 에 심어보고 싶네요 ^^

    • Favicon of https://www.cocoadev.co.kr BlogIcon cocoadev 2008.11.09 16:13 신고  댓글주소  수정/삭제

      보통 2~3일만에 되는 분들도 있고 몇주 걸리는 분들도 있는 것 같습니다. 정확히 어떤 이유에서인지는 잘 모르겠네요.

      빨리 처리되시기를 바랍니다. 좋은 말씀 감사합니다. :)

  11. 버들피리 2009.03.29 13:24  댓글주소  수정/삭제  댓글쓰기

    최근 SDK에서는 delegate 하는 부분이 바뀌었나 보네요. Connections Inspector 에 있네요. 우클릭이라는 글을 보면 당황하게 되네요. 맥마우스는 버튼이 하나인데.. 어디를 말하는 건지.. 제가 맥초보라 어제 샀거든요. ^^; 하여튼 유용하게 잘 보고 있습니다.

    • Favicon of https://www.cocoadev.co.kr BlogIcon cocoadev 2009.03.29 15:19 신고  댓글주소  수정/삭제

      아주 오래전 것이 아니라면 근래의 마이티 마우스는 투버튼을 지원을 하고 있습니다. 오른쪽 클릭을 해서 확인해 보세요. 아마 될 것 입니다. 만약 안되신다면 Ctrl + 마우스 클릭하시면 되고요. :)

  12. ssnmovie 2009.06.08 00:14  댓글주소  수정/삭제  댓글쓰기

    제가 원래 프로그램을 다루던 사람이 아니고요... 그래픽쪽 일을 하는 사람인데요...
    무작정 배워보고싶어 맥북 지르고...
    무료가입해서... Xcode 깔고... 해보고있는데요...
    좀 막막하네요..ㅜㅜ
    혹시 어떤식으로 공부를 해야하는지... 조언좀 해주신다면??
    무작정 따라해보고... 그럼.. 될까요??
    왜 이렇게 되는지는 잘 이해가 안되는데...ㅜㅜ

    • Favicon of https://www.cocoadev.co.kr BlogIcon cocoadev 2009.06.08 13:33 신고  댓글주소  수정/삭제

      아이폰 개발이 어려울 것은 없지만 프로그래밍 경험이 없으신 분들은 좀 막연할 수 있습니다. 이는 비단 아이폰 개발뿐만 아니라 다른쪽 개발도 마찬가지일 것이고요.

      방향이 어느정도 잡히고 뭔가가 보이기 전까지는 무조건 많이 따라해보고 조금씩 바꿔보고, 관련서적과 자료를 보시는 방법밖에 없을 것 같습니다. 좀 거시기한 말씀이지만.. 왕도는 없는 것 같습니다.

      관련된 커뮤니티나 동호회에 가입하셔서 다른분들과 같이 공부도 하고 궁금한 점을 물어 보시고 하는 것도 좋은 방법일 것 같습니다.

      그럼 힘내시고 수고하세요. :)

  13. 무작정따라하기 2009.06.23 17:50  댓글주소  수정/삭제  댓글쓰기

    무작정 따라 해 보고 있는데, build and go 해 보니까.
    실행할때 아래와 같은 메세지가 나오네요.

    Process: iBio [410]
    Path: /Users/towbtowb/Library/Application Support/iPhone Simulator/User/Applications/E25EFC08-263C-431E-848C-B64E6D19BCB5/iBio.app/iBio
    Identifier: iBio
    Version: ??? (???)
    Code Type: X86 (Native)
    Parent Process: launchd [110]

    Date/Time: 2009-06-24 02:08:12.649 +0900
    OS Version: Mac OS X 10.5.6 (9G55)
    Report Version: 6

    Exception Type: EXC_BREAKPOINT (SIGTRAP)
    Exception Codes: 0x0000000000000002, 0x0000000000000000
    Crashed Thread: 0

    Dyld Error Message:
    Library not loaded: /System/Library/Frameworks/UIKit.framework/UIKit
    Referenced from: /Users/towbtowb/Library/Application Support/iPhone Simulator/User/Applications/E25EFC08-263C-431E-848C-B64E6D19BCB5/iBio.app/iBio
    Reason: image not found

    대충 보니까. Frameworks 에서... 라이브러리가 로드 안된거 같은데.

    왜 그런지.. 아시는지 초보라서 일단 무작정 따라 해 보고 있습니다.

    • Favicon of https://www.cocoadev.co.kr BlogIcon cocoadev 2009.06.24 16:47 신고  댓글주소  수정/삭제

      저도 정확한 원인은 모르겠습니다. UIKit은 /Developer 밑에서 찾아야 되는데 좀 이상하네요. iPhone SDK 문제인지, 프로젝트 설정이 잘 못된 것인지, 어플 자체의 오류인지 확실히 모르겠습니다.

      새 아이폰 프로젝트도 이러면 SDK를 다시 설치하셔야 할 것 같고요. 지금 프로젝트만 이러면 설정이나 코드/IB 설정에 문제가 있는 것 같으니 프로젝트를 새로 만드신 후 복사하시거나 소스코드와 IB 연결상태, 속성들을 체크해 보셔야 할 것 같습니다.

  14. Munggu 2009.06.30 11:32  댓글주소  수정/삭제  댓글쓰기

    감사합니다 이제 막 시작해볼까 하는데 많은 도움이 될 것 같네요

  15. jickson98 2012.02.12 17:48  댓글주소  수정/삭제  댓글쓰기

    좋은자료입니다. 긍데 너무 오래 지나서 버젼이 안맞는지 오류가 생깁니다.

    위치는 bioView.m 파일에

    if (self = [super initWithFrame:frame])


    [self setNeedsDisplay];

    이 두 부분에서요. xcode4.2를 쓰고 있는데 어떻게 수정해야할까요?