아이폰 3.0 SDK 부터는 accelerometer를 사용하지 않고도 UIResponder에 추가된 motion 이벤트 처리 메소드를 구현함으로써 간단하게 사용자의 흔들기 동작을 체크할 수 있습니다. 저도 처음 사용해 보면서 간단한 내용들을 정리해 보았습니다.

1. First responder 되기
사용자의 흔들기 이벤트를 처리할 ViewController는 그 자신이 First responder가 되어야 합니다. becomFirstResponder 메소드를 호출하고 canBecomeFirstResponder 메소드에서 YES를 반환합니다.

  1. - (void)viewDidAppear:(BOOL)animated {
  2.     [super viewDidAppear:animated];
  3.     [self becomeFirstResponder];
  4. }
  5.  
  6. - (BOOL)canBecomeFirstResponder {
  7.     return YES;
  8. }

viewDidAppear는 코드에서 서브뷰로 추가될 때만 호출됩니다. IB에서 바로 Window에 View를 추가하였으면 awakeFromNib등의 메소드에서 becomFirstResponder를 호출하셔야 합니다.

2. motion 메소드 구현
이후로는 간단합니다. 사용자의 흔들기가 시작되면 해당 motionBegan이 호출되고 종료될 때 motionEnded가 호출됩니다. 지나치게 많이 흔들거나 하여 유효하지 않은 흔들기로 판단될 때는 motionCancelled가 호출됩니다.

  1. - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {
  2.     NSLog(@"Shaking start");
  3. }
  4.  
  5. - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
  6.     NSLog(@"Shaking end");
  7. }
  8.  
  9. - (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event {
  10.     NSLog(@"Shaking cancel");  
  11. }
  12.  

motionEnded 메소드에 사용자의 흔들기가 끝난 후 실행할 코드를 추가하면, 간단하게 흔들기를 지원할 수 있습니다.

모든 댓글을 환영합니다. (욕설과 광고는 삭제합니다.)
  1. TODD 2009.09.29 12:59  댓글주소  수정/삭제  댓글쓰기

    좋은 포스트 내용 잘 보았습니다.
    질문이 하나 있습니다.

    아이폰을 흔드는 것에 대해
    motionBegan, motionEnded, motionCancelled 등의 이벤트가 발생한다고 하셨는데요.
    저는 이런 이벤트가 존재하는지 조차 알기 어렵네요..

    상황에 맞는 이런 이벤트들의 리스트를 쪼로록 볼 수 있는 방법이 있나요?
    Visual Studio 환경에 익숙한 저로서는 OnKeyDown 같은 On~~ 으로 시작하는 이벤트 리스트 같은 것을 기대하고 있습니다.

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

      ESC나 F5 키를 누르시면 일치하는 메소드 리스트를 볼 수 있습니다. Help 메뉴의 리서치 어시스턴트를 활용하시면 관련 문서를 좀 쉽게 찾을 수 있습니다.

  2. Favicon of http://blog.windclimb.com BlogIcon 문군 2009.10.14 19:58  댓글주소  수정/삭제  댓글쓰기

    언제나 좋은 내용만 알려주시는 쩔님^^

    가끔 들어와서 업데이트 되엇나 쳐다보고 갑니다.

    저도 맥을 사용하는 유저인데...쩔님에게 많이 배우고 있습니다.

    항상 좋은 내용 많이 많이 올려주세요^^

  3. Favicon of http://icarusx.tistroy.com BlogIcon ICARUSX 2009.11.30 16:23  댓글주소  수정/삭제  댓글쓰기

    또 왔습니다 ^^
    아이폰 구매신청한상태인데 않오는군요 ㅎㅎ
    뭐 와도.. 구지 만들어서 테스트해볼만한게 없지만 ㅎㅎ

    좋은 강좌또보고갑니다 ^^
    아.. 그리고 결혼한답니다 ^^

    이리저리 인터넷에 아는 지인께 글남기는중.
    코코아데브님에게도 소식을 ㅋㅋ

    http://www.icarusx.com/icarusx/index.php?BD_NO=1023

    좋은 하루되세요 ㅎ

    • Favicon of https://www.cocoadev.co.kr BlogIcon cocoadev 2009.12.01 10:31 신고  댓글주소  수정/삭제

      이카루스님은 좋은 소식 풍년이네요. 이번에 예약하셨군요. 전 나중에 사기로 했습니다.

      가장 좋은 소식은 결혼 소식이네요. 축하드리며 행복한 가정 꾸리시기 바랍니다. :)

  4. 나그네^^ 2010.04.05 02:39  댓글주소  수정/삭제  댓글쓰기

    안녕하세요
    이 메소드를 cocos2d에서 사용할려면 어떻게 사용해야하는지 알려주실수있으신지요

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

      ViewController에서 받는 메시지니 해당 뷰클래스를 하나 만드셔야 될 것 같습니다. 구조를 어떻게 하실지 모르겠지만 cocoas2d의 Director에서 attach하는 뷰에 뷰컨트롤러를 만들어서 해당 메시지를 받으시면 될 것 같습니다.

  5. 수세미 2017.02.09 10:36  댓글주소  수정/삭제  댓글쓰기

    2017년에도 이글이 유효하네요. shake 잘 동작하네요. ^^



보통 Table View의 Cell은 코드로 만드는 경우가 많습니다. 여기서는 인터페이스빌더에서 Table View Cell을 사용하는 간단한 샘플을 만들어 보겠습니다.





1. 프로젝트 생성과 AppDelegate 변경
Xcode를 실행하고 "New Project"를 클릭하여 "Window-based Application"을 선택하여 프로젝트를 생성합니다. 저는 그냥 IBCell이란 이름으로 프로젝트를 만들었습니다.

1) IBCellAppDelegate.h

@class TableViewController;


@interface IBCellAppDelegate : NSObject <UIApplicationDelegate> {


IBOutlet TableViewController *tableViewController;

    UIWindow *window;

}

2
인터페이스 빌더에서 연결을 위해 tableViewController의 아울렛 변수를 추가합니다.

2) IBCellAppDelegate.m

- (void)applicationDidFinishLaunching:(UIApplication *)application {

  

[window addSubview:[tableViewController view]];

    // Override point for customization after application launch

    [window makeKeyAndVisible];

}


메인 윈도우의 SubView로 tableViewController의 View를 추가합니다.

2. ViewController
1) 생성
UIViewController subclass로 TableViewController란 이름으로 클래스를 생성합니다. SDK 3 부터는 "With XIB for user interface"가 있어 선택할 경우 ViewController 오브젝트와 연결된 별도의 xib를 자동으로 생성하여 줍니다. 여기서는 편의를 위해 선택하지 않았습니다.
* 2009/06/26 추가
오늘 확인해 보니 Objective-C class 선택시에 하단에 Subclass of로 선택할 수 있는 클래스들이 나오네요. 버젼업되면서 왜 줄었나 했더니 여기로 들어 가 있었습니다. 위의 방법말고 아래에서 UITableViewController를 바로 선택하고 사용하시면 됩니다.
 

2) TableViewController.h

#import <UIKit/UIKit.h>



@interface TableViewController : UITableViewController {

IBOutlet UITableViewCell *myCell;

}


- (IBAction)goMyBlog:(id)sender;


@end


부모 클래스를 UIViewController에서 UITableViewController로 변경합니다. 그리고 인터페이스빌더에서 연결을 위해 myCell 아울렛 변수를 추가합니다. 그리고 버튼 클릭시 연결될 goMyBlog 액션 메소드를 선언합니다.

3) TableViewController.m

/* 버튼 클릭시 */

- (IBAction)goMyBlog:(id)sender {

NSURL *url = [NSURL URLWithString:@"http://www.cocoadev.co.kr/"];

[[UIApplication sharedApplication] openURL:url];

}


#pragma mark Table view methods


/* 색션 */

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

return 1;

}


/* 색션 타이틀 */

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {

return @"소개";

}


/* */

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

return myCell;

}


/* 높이 */

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

return [myCell frame].size.height;

}


버튼 클릭시 실행될 메소드와 tableView의 delegate, datasource 메소드를 구현합니다.



3. 인터페이스 빌더

1) Table View Controller

인터페이스 빌더를 실행하고 라이브러리의 Controlls의 Table View Controller를 MainWindow.xib로 드래그해서 가지고 옵니다. Class를 TableViewController로 지정합니다.



좌측과 같이 Table View의 Style 속성을 Grouped로 지정합니다.



2) Table View Cell

라이브러리에서 Table View Cell을 MainWindow.xib로 드래그해서 가지고 옵니다.




아래와 같이 TableViewController의 myCell 아울렛에 가져온 Table View Cell을 연결합니다.


사용자 삽입 이미지
라이브러리 윈도우에서 Image View, Label, Rounded Rect Button, Text View를 드래그 해서 Table View Cell에 가져다 놓습니다.



Cell의 높이를 늘리고 각각의 컨트롤들을 아래와 같이 배치합니다. 적당한 이미지를 Xcode 좌측의 Groups & Files 아래의 Resources 그룹으로 드래그해서 프로젝트로 가져옵니다. Image View의 Image 속성에서 해당 이미지를 선택합니다. 입력이 되지 않도록 Text View의 Editable 속성의 체크를 해제합니다.
사용자 삽입 이미지

버튼 클릭시 사파리에서 해당 URL로 이동하기 위해 Text View Controller의 goMyBlog IBAction과 연결합니다.


4. 확인
Xcode에서 Build & Go를 클릭하면 시뮬레이터에서 아래와 같이 확인하실 수 있습니다.
SDK 3을 대충 보기만 하고 처음 사용해 보았는데 곳곳에 바뀐 부분이 눈에 뛰네요. SDK 3도 처음이고 오랫만에 포스팅이라 틀린 부분이 있는지도 모르겠습니다.

'iOS' 카테고리의 다른 글

아이폰 OS 4  (8) 2010.04.09
NSXMLParser로 RSS 읽어오기  (21) 2009.08.05
인터페이스빌더 Table View Cell 사용하기  (0) 2009.06.25
cocos2d 개발환경 설정  (24) 2009.04.13
iPhone SDK 3.0 beta 2  (4) 2009.04.05
UITableView의 메모리 누수 현상  (4) 2009.02.05
모든 댓글을 환영합니다. (욕설과 광고는 삭제합니다.)


iPhone 어플리케이션은 Xcode란 개발툴에서 코코아터치 프레임워크와 Objective-C 언어를 사용하여 개발합니다. 코코아 터치는 맥 OS X의 핵심 프레임워크인 코코아를 기본으로 아이폰/터치라는 모바일 기기의 특성에 맞추어진 iPhone 개발의 기본 API입니다.

그렇기 때문에 아이폰 어플리케이션 개발을 위해 기본적으로 알아야할 사항은 통합개발 환경인 Xcode와 인터페이스 빌더라는 툴의 사용법, Cocoa Touch 프레임워크, Objective-C 크게 세가지입니다. 이번에는 간단히 iPhone OS의 계층구조를 중심으로 iPhone 어플리케이션 제작을 위해 접근하는 방법에 대해서 알아 보겠습니다.

1. iPhone OS 계층 구조
아래의 그림은 애플에서 설명하는 아이폰 OS의 기술 계층입니다. 이에 대한 자세한 내용은 아이폰 개발자 센터iPhone OS Technology Overview란 문서에 잘 정리되어 있습니다.


가장 로우레벨의 Core OS부터 가장 상위단계인 코코아 터치까지의 계층구조입니다. 주로 하단은 API가 C로 제공되며 상위로 올라 오면서 Objective-C로 제공됩니다. 많이 사용되는 로우레벨의 API들은 상위단계에서 쉽고 편하게 사용할 수 있는 프레임워크로 제공됩니다. 간 계층의 간단한 설명은 아래와 같습니다.

1) Core OS
메모리/프로세서 관리, 파일 시스템, 네트워크, 각종 하드웨어 드라이버등, 운영체제 하단의 커널 레벨에서 제공하는 커널 API 입니다. 흔히 이야기하는 시스템 프로그래밍에 관련된 C를 기반으로 한 라이브러리를 제공합니다.

2) Core Services
Core Foundation, CFNetwork, SQLite, POSIX threads와 같은 파일입출력, 저수준 데이터 타입, 소켓등에 관련된 서비스입니다. Core OS 레벨에 비교적 쉽게 접근할 수 있는 API를 제공합며 대부분 C로된 프레임워크를 제공됩니다. 여기서 제공하는 많은 기능들은 상단 코코아터치의 Foundation Framework에서 Objective-C 프레임워크로 제공됩니다.

  • Core Foundation - 배열, 스트링, 날짜, URL, 로우레벨 데이터등 아이폰 어플리케이션을 위한 기본적인 C API를 제공합니다.
  • CFNetwork - BSD 소켓 및 HTTP, FTP 프로토콜등 네트워크에 쉽게 접근할 수 있는 API를 제공하는 프레임워크입니다.
  • Core Location - GPS, 주변검색등에 사용할 수 있는 사용자의 현재 위치(위도, 경도) 정보와 관련된 API를 제공하는 프레임워크입니다.
  • SQLite - 아이폰 어플리케이션에서 쉽게 사용할 수 있는 파일기반의 경량 데이터베이스 입니다. SQLite에 관련된 보다 자세한 내용은 이전 포스팅을 참조해 주세요.
  • XML - XML 파싱을 위한 libXML2 라이브러리를 제공합니다.

이외에 보안, 주소록등에 관련된 서비스를 제공합니다.

3) Media
비디오, 오디오, 2D/3D 그래픽, 에니메이션을 구현할 수 있는 API를 제공합니다. Objective-C 또는 C로된 API를 제공합니다.

  • Quartz - OS X의 벡터를 기반으로 한 그래픽 엔진입니다. 선과 도형을 그리고 이미지, 비트맵, PDF를 출력하고 색상, 위치에 관련된 C로된 API를 Core Graphic 프레임워크를 통해 제공합니다.
  • Core Animation - 각종 에니메이션과 시각효과를 제공하는 Objective-C로된 프레임워크입니다.
  • OpenGL ES - 게임등과 같은 고성능의 2D/3D 그래픽 출력을 위한 OpenGL ES 1.1에 기반한 C 프레임워크입니다. OpenGL ES를 사용한 게임은 이를 지원하는 다양한 모바일 플랫폼에서의 포팅을 쉽게 할 수 있습니다. 자세한 내용은 공식 홈페이지를 참조하시기 바랍니다.
  • Core Audio - 마이크를 통해 녹음하고 음악파일을 출력하고 각종 음향효과를 제공하는 C로된 오디오 관련 프레임워크입니다.
  • OpenAL - OpenGL ES와 유사한 개념의 크로스 플랫폼을 지원하는 게임등을 위한 고성능 3D 오디오 라이브러리입니다. 자세한 내용은 공식 홈페이지를 참조 하시기 바랍니다.
  • 동영상 - mov, mp4, 3gp와 같은 각종 동영상 파일을 출력을 지원합니다. 이는 Objective-C를 기반으로 한 Media Player framework를 이용하여 손쉽게 접근할 수 있습니다.

4) Cocoa Touch
iPhone개발의 기본이 되는 계층으로 Objective-C를 기반으로 한 핵심적인 두개의 프레임워크를 가지고 있습니다. 사용자 인터페이스, 이벤트 처리등과 함께 위에서 언급한 로우레벨의 기술들을 보다 쉽게 사용할 수 있는 프레임워크를 제공합니다.

  • Foundation Framework - 배열, 스트링, 날짜 로우레벨 데이터등에 관련된 클래스를 제공하는 기본적인 프레임워크입니다. 위의 Core Foundation에서 제공하는 기본 API들의 Objective-C 레퍼 클래스를 제공합니다.
  • UIKit Framework -각종 컨트롤, 윈도우등의 UI, 이벤트 처리등 iPhone 어플리케이션의 사용자 인터페이스와 관련된 API를 제공하는 프레임워크입니다.


2. Mac or iPhone
Mac의 Cocoa와 iPhone의 Cocoa touch는 이름에서 부터 알 수 있듯이 매우 비슷합니다. 가장 큰 차이점은 역시 인터페이스에 관련된 부분으로 이와 관련하여 Mac에서는 AppKit이란 프레임워크를 iPhone에서는 UIKit이란 프레임워크를 제공합니다.

Foundation Framework는 거의 유사하지만 아이폰의 특성상 제거 또는 변경된 부분이 있습니다. 아이폰은 코코아 바인딩, Objective-C 2.0의 가비지 컬렉션, 애플스크립트, NSUndoManage등은 지원하지 않습니다.

개인적으론 시간이 충분하다면 맥에서 코코아 프로그래밍으로 시작한 후에 코코아 터치로 넘어가도 큰 어려움은 없을 것 같습니다.


3. C or Objective-C
대표적인 코코아 프로그래밍 서적인 Cocoa Programming for MAC OS X (번역본:코코아 프로그래밍)의 저자 아론 힐리가스는 그의 저서에서 아래와 같이 이야기 했습니다.

"C와 Java/C++같은 객체지향 언어를 알고 있다면 두시간이면 Objective-C를 마스터할 수 있다"

OOP와 프로그래밍 언어에 대한 개념만 있다면 Objective-C를 익히는 것은 쉽다라는 의미인 것 같습니다.

사실 어느 언어나 기본지식만 있으면 언어 자체를 익히는데는 그다지 어려움이 없습니다. 하지만 해당 플랫폼에 대한 지식과 핵심 라이브러리나 프레임워크를 배우는데 더욱 많은 시간을 소비해야 합니다. 아이폰도 Xcode, 인터페이스빌더의 사용법, OS X에서의 프로그래밍에대한 이해와 코코아 API를 배우는데 Objective-C 언어 자체를 배우는 것보다 더 많은 시간이 필요합니다.

1) C의 선행학습이 필요한가?
개발경험이 있으신 분들은 그동안의 경험을 바탕으로 어떻게 공부해야 할지 나름대로 방법이 있을 것입니다. 하지만 처음 시작하시는 분들은 Objective-C가 C를 기반으로 하고 있기 때문에, 반드시 C를 공부한 후에 Objective-C를 공부해야하는 지에 대해 질문을 하시는 분들이 있습니다.

이 부분은 아마 많은 분들이 차이가 있을 것 같습니다. 제 생각은 "반드시 필요하지는 않다" 입니다. Objective-C는 C에서 확장된 슈퍼셋이라고 하지만 Objective-C를 공부하기 위해 반드시 C를 먼저 공부해야 할 필요는 없을 것 같습니다.

C를 이해한 후에 Objective-C를 시작하는 것이 이론상으로도 맞고, 정상적인 방법일 것입니다. 하지만 대부분의 Objective-C 서적이나 메뉴얼에는 기본적인 문법에 대한 설명이 있고, 전문 C 서적보다는 범위가 작습니다. Objective-C를 사용할 수 있을 만큼 최소한의 문법만 알고 시작하는 것이 더 접근이 쉬울 것 같습니다.

아래는 iPhone 어플케이션의 샘플 소스중에 한부분입니다. 기존에 C/C++ 개발자들도 이런 Objective-C의 문법을 처음 보게되면, 이것이 C와 관련이 있고 C에서 확장되었다는 사실이 잘 이해가 가지 않을 것입니다.
 

처음 시작하시는 분이라면 차라리 이런 혼란을 피하고 코코아 어플리케이션을 바로 제작할 수 있는 Objective-C로 시작하는 것도 한 방법이라고 생각됩니다.

2) 접근방법
사실 가장 좋은 것은 아래와 같이 가장 로우레벨단계 부터 이해하고 올라 가는 것이 기초도 탄탄하고 가장 좋은 방법일 것입니다.

  1. 메모리/CPU등 컴퓨터 하드웨어에 대한 이해
  2. OS에 대한 이해
  3. 컴파일러에 대한 이해
  4. C언어
  5. 시스템 프로그래밍
  6. 자료구조/알고리즘
  7. Objective-C
  8. OOP, 디자인 패턴
  9. Cocoa API

위의 단계대로 차례로 지식과 실력을 쌓아서 접근하면 좋겠지만, 당장 아이폰 어플리케이션을 만들고 싶은데 지루하고 많은 시간을 필요로 합니다. 흥미를 잃지 않고 접근하는 방법은 위의 순서와 반대로 접근하는 것입니다.

Objective-C에 대한 메뉴얼을 대충(?) 한번 읽어 보고 바로 책, 웹사이트, 동영상등의 간단한 튜토리얼등을 따라해 보면서 실제 실행되는 모습을 보면 계속 흥미를 유지할 수 있습니다.

그후에 어느정도 감이 생기면 직접 만들고 싶은 어플리케이션을 목표로 잡습니다. 첫 목표는 과한 욕심은 버리고 간단하고 쉬운 어플리케이션 부터 시작합니다. 아무리 간단해도 따라해 보며 만들었던 것과는 달리 원하는 기능을 직접 구현하는 것은 매우 어렵습니다. 자료도 많이 찾아 보아야되고, 다른 샘플 소스에서 복사해 와야 하는 경우도 있고, 관련 커뮤니티를 통해 도움을 받을 수도 있습니다. 관련자료들은 이전의 iPhone 어플리케이션 개발을 위한 준비 - 3. 관련 자료 포스팅을 참고하시기 바랍니다.

우여곡절끝에 만들어 내면 부족한면이나 필요한 부분이 무엇인지 조금씩 보이게 될 것 입니다. 필요에 의해 공부를 하다보면 아마 위의 순서를 거슬러 올라 접근하게 되는 경우가 많을 것 같습니다. 그러면 차차 복잡하고 어려운 어플리케이션을 만들 수 있을 것입니다.

막상 처음 시작하게 되면 알아야 할 것은 많고 답답한 마음만 드실 것입니다. 하지만 안타깝게도 왕도는 없습니다. 흥미와 열정을 유지하면서 차근차근 해 나가다 보면 어느새 바라는 어플리케이션을 만들수 있는 날이 눈앞에 와있을 것 입니다.

간혹 주위에 개발경험이 전혀 없는 분들로 부터 "무엇부터 시작해야 아이폰 어플리케이션을 만들 수 있냐?"는 질문을 들으면서 이와 관련해서 간단히 포스팅을 해보아야 겠다고 생각했습니다.

정리는 해보았는데 역시 어렵네요. 제가 봐도 이상한 용어들만 난무하고 설명도 중구난방이고, 개발을 처음 하시는 분들이 보면 잘 이해가 안가실 것 같다는 생각이 듭니다.

* 관련링크
iPhone 어플리케이션 개발을 위한 준비 - 1. 하드웨어
iPhone 어플리케이션 개발을 위한 준비 - 2. 소프트웨어
iPhone 어플리케이션 개발을 위한 준비 - 3. 관련 자료
iPhone 어플리케이션 개발을 위한 준비 - 4. 시작하기
모든 댓글을 환영합니다. (욕설과 광고는 삭제합니다.)
  1. 달룟 2008.12.23 18:23  댓글주소  수정/삭제  댓글쓰기

    점점 책이 되어가네요^^

  2. yuripapa 2008.12.24 02:25  댓글주소  수정/삭제  댓글쓰기

    아주 예전 예전 예전에 NextStep에서 돌아간다는 코드를 본적이 있습니다.
    그게 제 기억으로 Objective-C로 알고 있구요.. 지금도 NS를 붙이고 있죠..
    C랑 Smalltalk을 섞었다고 들었는데...
    저 역시도 깊이있게는 아직 못봤지만... C를 따로 하지말고 바로 들어가는게.. ^^

    • Favicon of https://www.cocoadev.co.kr BlogIcon cocoadev 2008.12.24 10:27 신고  댓글주소  수정/삭제

      C를 알고 시작하는 것이 당연히 더 좋겠지만, C에 익숙해지는데도 시간이 꽤 들어 가기 때문에 쉽게 지칠 수도 있다는 생각이 듭니다. 저도 흥미를 잃지 않게 접근하는 것이 좋을 것이라 생각되네요. :)

  3. Favicon of http://www.secretpaper.net BlogIcon 시크릿페이퍼 2009.01.07 23:00  댓글주소  수정/삭제  댓글쓰기

    책보다 훨씬 유용하네요 ^^
    잘 읽고 있습니다

  4. denny 2009.01.29 20:50  댓글주소  수정/삭제  댓글쓰기

    정성이 대단하십니다. 좋은글 잘 봤습니다^^

  5. dooly 2009.03.25 03:43  댓글주소  수정/삭제  댓글쓰기

    감사합니다. 이런 공들인 훌륭한 포스팅 처음 봅니다^^
    광고도 안 올리시고,.. 이런 순수한 의도 다른곳에선 정말 보기 드문것 같습니다.

  6. ckd 2009.07.14 17:59  댓글주소  수정/삭제  댓글쓰기

    진작에 이 포스팅을 찾았으면 되었을 것을..
    제게 필요한 자료만 쏙쏙 있네요.
    인터넷 웹서핑한다고 몇 시간을 날렸는데.. .ㅠ.ㅠ
    진작 여기 와 볼걸 그랬어요.... 내 시간.. ㅎ

  7. Darc 2009.11.13 15:48  댓글주소  수정/삭제  댓글쓰기

    정말 좋은 내용 감사합니다. 매일 출근해야 겠네요 ^^:

  8. 쉬인 2011.05.04 12:12  댓글주소  수정/삭제  댓글쓰기

    정말 와닿네요.
    이제 겨우 xml 파싱을 통해 테이블 뷰에 뿌리는 정도를
    혼자 할 정도로 외우다시피(?)하는 과정인데
    사실 이해가 좀 부족하면서도 계속 반복하고 있는 중입니다.

    신기하게도 같은 코드지만 반복할때마다 의미가 조금씩 보이는거 같아요.

    공부하는 순서표(?)에서 하나의 방법으로 거꾸로 시도해보는 것도 좋다는 글이
    정말 와닿네요.
    지금 제모습 같아서요.

    지금은 안드로이드쪽으로 가셔서 뜸하신듯 하지만, 지금의 제겐 아주 많은 도움이 됩니다.
    고맙습니다^^

  9. 서희상 2014.07.07 16:37  댓글주소  수정/삭제  댓글쓰기

    잘정리해 두셨네요 고생하셧습니다. ㅎㅎ



iOS 2008. 11. 22. 14:33
오늘 맥을 켜니 아이튠즈와 함께 아이팟 터치 펌웨어도 2.2로 업그레이드 되었습니다. 애플 사이트에서 가져온 아이폰 펌웨어 2.2에서 변경된 내역은 아래와 같습니다.

* Enhancements to Maps
  • Google Street View*
  • Public transit and walking directions
  • Display address of dropped pins
  • Share location via email
* Decrease in call setup failures and dropped calls

* Enhancements to Mail
  • Resolved isolated issues with scheduled fetching of email
  • Improved formatting of wide HTML email
* Podcasts are now available for download in iTunes application (over Wi-Fi and cellular network)

* Improved stability and performance of Safari

* Improved sound quality of Visual Voicemail messages

* Pressing Home button from any Home screen displays the first Home screen

* Preference to turn on/off auto-correction in Keyboard Settings

사파리로 브라우징시에 간혹 튕기는 현상이 있었는데, 사파리의 안정화 부분 정도에만 눈길이 가네요. 캘린더에 TODO 기능과 iCal과의 동기화가 되었으면 좋겠는데, 애플에서 언제쯤 넣어줄지 모르겠습니다.

완료후에 iPhone DevCenter로 가보니 역시 SDK도 동일하게 2.2로 업그레이드 되었습니다. SDK를 새로 설치하니 Xcode도 3.1.1에서 3.1.2로 업그레이드 되었습니다.

IDE나 Core의 버젼이 올라갔지만 펌웨어에 맞추어 2.2로 업그레이된 것을 제외하고는 문서를 읽어보아도, 실행해서 대충 둘러 보아도 눈에 뛰게 변경된 점은 없는 것 같습니다.
모든 댓글을 환영합니다. (욕설과 광고는 삭제합니다.)
  1. 달룟 2008.11.22 21:55  댓글주소  수정/삭제  댓글쓰기

    혹 아이폰SDK에 Color Well이 추가되지는 않았나요?

  2. yuripapa 2008.11.23 03:25  댓글주소  수정/삭제  댓글쓰기

    역시나 폰 기능이 자꾸 좋아지는군요... 아~~ 근데 우린 언제 아이폰 쓰죠? ㅠ.ㅠ
    SDK업데이트 소식은 여기서 첨 알았네요... =^^=

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

      몇일 전 만난 분의 말씀으로는 곧 나온다고 하던데, 소식은 안들리네요. SDK 자체는 변화가 없기 때문에 여기에 별 관심 쏟을 일은 없는 것 같습니다. :)



등록신청하고 2주정도만에 겨우 완료했습니다. 단계마다 오류가 있어 애플과 몇번의 메일을 주고 받다가 오늘 무사히 등록했습니다. 등록후에는 아이폰 개발자 포탈에서 iPhone Developer Program Protal User Guide란 문서를 다운로드 받아 설명한대로 진행하니 별다른 어려움 없이 개발환경을 완료할 수 있었습니다.

편하게 사용할려고 App ID 생성시에 번들아이디를 와일드카드(*)로 지정했는데, 터치로 컴파일시에는 문제가 없었습니다. 배포시에는 문제가 될지 모르겠지마, 다시 생성하면 되니 일단은 저 App ID 하나로 쓰기로 했습니다.


모든 인증 완료 후에 아이팟 터치를 아이튠즈에서 동기화를 하고나니, 아래와 같이 설정/일반에 프로파일 항목이 추가되어 있습니다.


테스트를 해볼려고 Xcode를 실행하니 아래와 같은 오류가 났습니다.

SDK를 다시 설치할려다가 자료를 찾아 보니 아이팟 터치 2세대로 개발을 할 때는 아래와 같이 심볼릭 링크를 해주어야 한다고 합니다. 아래와 같이 심볼릭링크를 생성하니 위의 오류 메시지는 없어졌습니다.

> cd /Developer/Platforms/iPhoneOS.platform/DeviceSupport
> ln -s 2.1 2.1.1

프로젝트의 빌드 설정에서 아래와 같이 iPhone Developer를 제 이름으로 설정하고 Profile을 설정하고, 빌드를 하니 제 아이팟 터치에도 잘 올라가고 실행도 잘되네요.


이제는 뭘 만들어서 올리는 일만 남았는데, 뭘 만들어야 할지 모르겠네요.
모든 댓글을 환영합니다. (욕설과 광고는 삭제합니다.)
  1. 달룟 2008.11.05 14:56  댓글주소  수정/삭제  댓글쓰기

    많이 기다렸습니다.
    이제는 Xcode설명도 모자라, 아이폰 등록하는 법까지!!
    이 블로그는 아이폰 개발자들의 필독 블로그네요.

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

      등록하는 법은 별로 없는데요. ^^;; 사실 과정을 정리해서 올릴려고 했는데, 중간에 오류가 너무 많이 있어서 그냥 마무리만 올려 보았습니다. 좋은 말씀 감사합니다. :)

  2. Favicon of http://sukwoo.blogspot.com BlogIcon 장림 2008.11.05 14:59  댓글주소  수정/삭제  댓글쓰기

    축하합니다. ^^

  3. Felix 2008.11.05 15:22  댓글주소  수정/삭제  댓글쓰기

    부럽습니다. ^^

  4. Favicon of http://icarusx.com BlogIcon ICARUSX 2008.11.06 00:16  댓글주소  수정/삭제  댓글쓰기

    안녕하세요 ^^ 다른사이트에서 강좌를 잘보고
    이곳까지 와서 공부중입니다 ^^
    기존에 작년부터 자주 왔다리 갔다리 했습니다만;;
    저번달부터 아이폰어플관련 공부를 본격적으로 시작중입니다.
    완전 초보죠 ㅎㅎ;;

    다름이아니고.. 어떤 강좌를 부탁드리려고합니다 -_-;;
    민폐겠지요??

    아이팟터치와 아이폰이 인터넷없으면 거의쓸일이 없는저로써..
    웹프로그래밍과 3d 디자이너였던 저에게.
    개발해보고픈 부분이 있는데..

    개념을 못잡아서 헤메고있습니다.

    사막에 오아시스같은 바이오리듬 강좌를 보고
    혹 가능하시면 강좌나 팁좀 부탁드립니다..

    부탁하고싶은 부분은.

    웹에서 때려주는 xml 를 아이폰 sdk 로 받을수있고.
    이미지나 어떤 음악파일, 동영상(힘들겠지만) 까지 보여줄수있는부분입니다.

    웹의 자료를 보여줌과 동시에 웹의 필요한 자료를 아이팟에서 보관가능케까지
    하는부분이 제목적입니다..

    가능하시면 부탁드립니다.
    xellossdh@naver.com으로 연락좀 부탁드려요 ^^
    강좌라도 ㅠㅠ

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

      안녕하세요. 이카루스님 반갑습니다. :)

      xml은 NSXML*을 사용하시면 접근하기 쉬울 것 같습니다. 아이폰에서 파일송수신은 저도 잘 모르겠네요. 확답은 못드리겠지만, 제가 공부하는데로 블로그에 올리겠습니다.

    • Favicon of http://icarusx.com BlogIcon ICARUSX 2008.11.06 21:16  댓글주소  수정/삭제

      아 감사드립니다 ^^
      xml관련정보랑 공부하시면 바로 올리신다는 리플에 ㅎㅎㅎ 감사드려요 ㅎㅎ

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

      xml은 NSXMLDocument를 사용하시면 쉽게 관리하실 수 있습니다. 제가 말씀드린 건 파일 저장에 관련된 내용이고요. ^^;;

      아무튼 xml도 시간나는대로 간단히 올려 보겠습니다. :)

  5. Favicon of http://jasonpa.com BlogIcon JasonPA 2008.11.06 15:23  댓글주소  수정/삭제  댓글쓰기

    아아 이런 전 SDK 를 다시 인스톨 하고서 위와 같은 다이얼로그를 한번 더 본 상황에서 이 포스팅을 보게 되었네요. 미리 보았으면 좋았을 것을 ^^ 감사합니다.

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

      Pre-Installation Advisory란 문서에 언급은 되어 있지만, 이런 사항은 애플에서 신경을 좀 써야돼지 않았나 생각됩니다.

      방문해 주셔서 좋은 말씀 감사합니다. :)

  6. 2008.11.11 21:10  댓글주소  수정/삭제  댓글쓰기

    비밀댓글입니다

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

      헉, 답변을 드린 것 같은데 없네요.

      아무튼 말씀하신 내용은 참 좋은 아이디어인 것 같습니다. 전 왜 그런 생각이 안떠오르는지... ^^;;

  7. Favicon of https://mazicky.tistory.com BlogIcon Zicky 2008.12.08 22:47 신고  댓글주소  수정/삭제  댓글쓰기

    아이폰 대학생 개발자 프로그램 무료 등록하려고했는데..

    미국학생밖에 안되나봐요 ㅠㅠ

    최근에 아이폰 터치 2세대 구입하고 , 개발해서 바로 넣어서 실행해 볼줄알았는데^^;

    일단 공부해서 시뮬레이터로 돌려보고, 일반 개발자로 돈내고 등록해야겠습니다^^

    근데.. 환율때문에... 99달라가 ㅠ_ㅠ


    자주 들러서 정보 얻어가겠습니다^^

    • Favicon of https://www.cocoadev.co.kr BlogIcon cocoadev 2008.12.09 10:52 신고  댓글주소  수정/삭제

      아직은 미국만 해당되는 것 같은데, 우리나라도 적용될 날이 빨리 왔으면 좋겠습니다. :)

      개발자등록은 아직 오른 환률 적용을 안받는 다고 언뜻 들은 것 같은데 확실하지는 않습니다.

  8. Favicon of http://reshout.com BlogIcon reshout 2009.01.24 11:13  댓글주소  수정/삭제  댓글쓰기

    아아팟 터치에서 실행해 보려면 반드시 아이폰 개발자 프로그램에 등록해야 하나요? 그냥 해보니까 잘 안되더라구요.

  9. 이민영 2009.02.05 15:18  댓글주소  수정/삭제  댓글쓰기

    안녕하세요.. 우여곡절끝애 IPHONE 개발등록신청까지 끝내고 상품등록 다 끝내고 나서
    이제 좀 테스트 해볼까하고 디버그 하려고 하는데...

    codesign: unrecognized option `--entitlements'

    라는 에러가 떠서요.. 외국싸이트 하며 다 찾아봤는데 ..
    이 에러 에 대해서는 안나와있더라구요..
    혹시 저랑 같은 에러메세지가 나오신 분이 계시다면 어떻게 처리 하셨는지 여쭤보고자
    왔습니다.

    이 에러도 3일째 고생하고 있는데요... 도..도와주시면 정말 감사하겠습니다.

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

      저 오류메시지는 본것 같기도 하고 못 본것 같기도 하고 기억이 잘 안네요. 저도 해결방법은 잘 모르겠습니다.구글에서 codesign: unrecognized option으로 검색하시면 관련된 내용이 많이 있습니다. 이민영님과 같은 조건의 사례를 찾아 보시고 참조하시면 될 것 같습니다.

  10. shock 2009.02.13 16:18  댓글주소  수정/삭제  댓글쓰기

    개발자 프로그램 구입을 방금 맞췄답니다.
    이제 처리 완료가 되기를 기둘리고 있답니다.
    그런데 제가 개발용으로 사용하는 PC가 맥이 아니라 Dell 노트북에 헤킨토시를 설치해서
    사용하고 있기 때문에 유/무선 이터넷이 전혀 안된답니다.
    인증서를 다운로드 받아서 설치할때 XP 로 다운로드 받고 UBS 메모리로 복사해서 MAC 에 다시 집어넣는게 가능한가요?
    다음 단계를 어떻게 해야하는지 잘 몰라서 질문 올려봅니다 ^^;

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

      저도 해본적은 없지만 PC에서 다운로드 받은 후에 맥으로 파일을 가져와서 설치하는 것은 가능할 것 같습니다. 인터넷이 안되면 불편하실 것이 많으실 것 같은데, 맥미니라도 하나 장만 하심이... ^^;;



PickerView, ImageView, TableView를 이용한 간단한 예제입니다. 좌측의 테이블뷰나 하단의 피커뷰에서 moveIn, push, reveal, fade 효과를 선택하면 우측의 이미지가 해당 효과로 다음 이미지와 변환되는 간단한 샘플입니다. 피커뷰의 2번째 컴퍼넌트에서는 효과가 진행되는 방향을 설정합니다. fade 효과에서는 이 방향이 적용되지 않습니다.

(사용한 샘플 이미지에 대해선 사과 드립니다)

이 샘플은 애플의 아이폰 DevCenter의 샘플코드중에서 UICatalogView Transitions 를 참조하였습니다.

1. 프로젝트 생성

Xcode의 메뉴에서 File / New Project를 클릭합니다. iPhone OS / Application을 선택하고 View-Based Application 템플릿을 선택하고 Choose..를 클릭합니다.


적당한 프로젝트명을 입력하고 Save를 클릭하여 프로젝트를 생성합니다. 여기서는 Control2로 생성하였습니다.


2. 소스코드 수정
Control2ViewController의 소스와 헤더 파일에 아래의 푸른색으로 되어 있는 부분을 입력합니다. 설명은 간단한 주석으로 대체하겠습니다.

1) Control2ViewController.h
#import <UIKit/UIKit.h>

@interface Control2ViewController : UIViewController {

    IBOutlet UITableView *myTableView;
    IBOutlet UIPickerView *myPickerView;
    IBOutlet UIView *myView;
   
    UIImageView *imageView1;
    UIImageView *imageView2;
   
    NSArray *effectArray;
    NSArray *directionArray;
}

@end

2) Control2ViewController.m
#import "Control2ViewController.h"
#import <QuartzCore/QuartzCore.h>

@implementation Control2ViewController

static NSString *kCellIdentifier = @"MyIdentifier";
static NSString *kAnimationKey = @"transitionViewAnimation";

- (void)viewDidLoad {
    [super viewDidLoad];
   
    // 에니메이션 효과들을 배열로 저장
    effectArray = [[NSArray arrayWithObjects:kCATransitionMoveIn, kCATransitionPush,
                    kCATransitionReveal, kCATransitionFade, nil] retain];
   
    // 에니메이션 시 진행방향을 배열로 저장
    directionArray = [[NSArray arrayWithObjects:kCATransitionFromLeft, kCATransitionFromRight,
                       kCATransitionFromTop, kCATransitionFromBottom, nil] retain];
   
    // 이미지 뷰 생성
    imageView1 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"no1.png"]];
    imageView2 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"no2.png"]];
   
    // 이미지 뷰 크기 설정
    CGRect rect;
   
    rect.origin = CGPointZero;
    rect.size = [myView frame].size;
       
    [imageView1 setFrame:rect];
    [imageView2 setFrame:rect];

    // 첫번째 이미지 뷰 추가
    [myView addSubview:imageView1];
}

- (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 {
    [imageView1 release];
    [imageView2 release];
   
    [effectArray release];
    [directionArray release];
   
    [super dealloc];
}

#pragma mark Animation methods

/** 에니메이션 실행 */
- (void)transitionView:(NSUInteger)effect
{
    UIView* newView;
    UIView* oldView;
   
    // 나올 뷰와 사라질 뷰를 설정
    if ([imageView1 superview] == myView) {
        newView = imageView2;
        oldView = imageView1;
    } else {
        newView = imageView1;
        oldView = imageView2;
    }
   
    // 이전 뷰를 삭제하고 새로운 뷰를 등록
    [oldView removeFromSuperview];
    if (newView && ([newView superview] == nil)) {
        [myView insertSubview:newView atIndex:1];
    }
   
    // 에니메이션 효과와 방향을 설정
    NSString *transition = [effectArray objectAtIndex:effect];
    NSString *direction = [directionArray objectAtIndex:[myPickerView selectedRowInComponent:1]];
   
    // 에니메이션
    CATransition *animation = [CATransition animation];
   
    // 변환효과 설정
    if (transition == kCATransitionFade) {
        [animation setType:kCATransitionFade];
    } else {
        [animation setType:transition];
        [animation setSubtype:direction];
    }
   
    // 변환속도 설정
    [animation setDuration:0.75];
    [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
   
    [[myView layer] addAnimation:animation forKey:kAnimationKey];
}   


#pragma mark TableView delegate/dataSource methods

/** 테이블뷰의 선택이 변경되었을 경우 */
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    // PickerView의 효과 컴포넌트 선택 변경
    [myPickerView selectRow:[indexPath row] inComponent:0 animated:TRUE];
   
    // 에니메이션 실행
    [self transitionView:[indexPath row]];
}

/** 테이블뷰 섹션 수 */
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

/** 테이블뷰 row count */
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [effectArray count];
}

/** 테이블뷰 각 항목 타이틀 설정 */
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:kCellIdentifier];
    if (cell == nil)
    {
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:kCellIdentifier] autorelease];
    }
   
    cell.text = [effectArray objectAtIndex:indexPath.row];
   
    return cell;
}

/** 색션 해더 타이틀 설정 */
- (NSString *)tableView:(UITableView *)aTableView titleForHeaderInSection:(NSInteger)section
{
    return @"Effect";
}


#pragma mark PickerView delegate/dataSource methods

/** 피커뷰의 선택이 변경되었을 경우 */
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    // componet가 0(첫번째 컴퍼넌트)일 경우에만 처리
    if (component == 0) {
        // 테이블뷰의 선택된 row 변경
        [myTableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:component]
                                 animated:NO
                           scrollPosition:UITableViewScrollPositionTop];
   
        // 에니메니션 실행
        [self transitionView:row];
    }
}

/** 피커뷰의 컴퍼넌트 수 설정 - 2(효과, 방향) */
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
    return 2;
}

/** 피커뷰의 각 컴퍼넌트의 row count */
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
    if (component == 0)
        return [effectArray count];
    else
        return [directionArray count];
}

/** 피커뷰의 각 컴퍼넌트의 항목 타이틀 설정 */
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
    if (component == 0)
        return [effectArray objectAtIndex:row];
    else
        return [directionArray objectAtIndex:row];
}

@end


3. 인터페이스 빌더

이제 인터페이스 빌더에서 UI를 생성하고 속성들을 연결해 보겠습니다.

Groups & Files의 Resources 폴더에서 Control2ViewController.xib를 더블클릭하여 인터페이스 빌더를 오픈 합니다.

1) 컨트롤 배치
라이브러리 윈도우에서 View, TableView, PickerView를 각각 드래그 해서 아래와 같이
View에 배치합니다.

2) Outlet 연결
xib 윈도우에서 File's Owner를 우클릭 합니다. 여기서 File's Owner는 Control2ViewController 입니다. 각 Outlet들을 위에서 생성한 컨트롤들과 연결합니다. myPickerView를 PickerView와 myTableView를 TableView와 myView를 View로 연결합니다.
 

이제 작업이 완료되었습니다. 빌드를 하고 테스트를 하여 봅니다. 아래는 전체 프로젝트를 압축한 파일입니다.


모든 댓글을 환영합니다. (욕설과 광고는 삭제합니다.)
  1. 달룟 2008.10.14 12:38  댓글주소  수정/삭제  댓글쓰기

    사진에서 비명을 질러버렸습니다. 처다보네요.

  2. 달룟 2008.10.14 12:49  댓글주소  수정/삭제  댓글쓰기

    가비지컬랙터에 익숙해서인지, release를 거의 하지 않는 습관이 들어버렸습니다. 나중에 고생할 듯...

  3. 달룟 2008.10.14 12:51  댓글주소  수정/삭제  댓글쓰기

    Control2.zip은 .framework들이 모두 빨간색(不在)으로 컴파일이 안되네요. 으... 이럴 때가 제일 무섭다는...

  4. Favicon of http://www.cliff3.net/ BlogIcon cliff3 2008.10.14 16:23  댓글주소  수정/삭제  댓글쓰기

    RSS 리더로 보다가 기절할 뻔 했습니다. ㅋㅋㅋ
    조만간 오프모임에서 뵙도록 하겠습니다. :-)



맥 OS X의 코코아에서의 개발에 관심이 있는 분들이 그리 많지 않았습니다. 올해 초까지만 하더라도 인터넷을 제외하고 현실에서 코코아 개발에 관심을 가지고 있는 사람들을 직접 만난 적이 없었습니다. 간혹 지인들에게 '맥에서 개발의 재미'에 대해서 이야기를 해도 그냥 그런가 보다라고 시큰둥하게 받아 들이는 것이 대부분이었습니다.

하지만 애플에서 올해 초 iPhone SDK를 공개되고 App 스토어가 오픈되면서 개발자들의 관심이 서서히 높아가고 있는 것 같습니다.

좌측은 구글 접속통계에서 본 제 블로그의 올해 방문자 통계입니다.  제 블로그의 방문자 수는 시작부터 계속 일직선으로 항상 일정했습니다. 하지만 애플의 App 스토어가 오픈되면서 부터 조금씩 증가하기 시작했습니다. 한낱 개인 블로그의 방문자 수로 단정 짓기는 어렵지만 관심있는 업체나 개인이 조금씩 늘어 가고 있구나 하고 짐작하고 있습니다.

이는 아마존에서 나오는 신간을 봐도 알 수 있습니다. 이전에는 Xcode나 코코아에 관련된 책들은 가뭄에 콩나듯이 새책이 나왔습니다. 그런데 요즘은 아마존에서 오는 신간 안내 메일만 봐도 허풍을 조금 보태면 아이폰 관련 서적이 자고 일어나면 하나씩 나오는 것 같습니다.

사용자 삽입 이미지
(출처:amazon.com)

그외에도 우리나라에서는 osxdev.org외에는 거의 전무했던 맥 개발 관련 사이트와 까페들이 조금씩 늘어 가고 있습니다.


저도 한 까페에 가입하여 오브라인 모임도 자주 참석하고 글도 쓰면서 나름 열심히(?) 참여있습니다. 회원들이 대학생들이 많아 나이 차이가 꽤 크지만 같은 관심을 가진 분들과 교류한다는 것은 즐거운 일인 것 같습니다.

이야기를 들어 보면 역시 맥 보다는 아이폰에서의 개발에 관심을 가진 업체나 개인들이 많았습니다.

마케팅과 세일즈에 크게 노력을 하지 않고 개발 자체에만 집중하면 된다는 점과 App 스토어라는 세계를 상대로 하는 커다란 시장이 개발자들에게 매력적으로 다가 오지 않았나 하는 생각이 듭니다. 그리고 아직 초창기이기 때문에 많은 가능성도 가지고 있고요.

하지만 막상 우리나라에서 아이폰 출시는 루머만 무성하고 난항을 겪고 있습니다. 저는 개발 용도가 아닌 제 일상 생활의 편의와 재미를 위해서 간절히 출시를 바라고 있는데, 더 이상 조바심 내지말고 출시되기 전까지는 신경을 끄고 있기로 했습니다.

일본에서는 아이폰 판매가 기대보다는 저조했다고 하던데, 한국에서 출시가 되면 결과가 궁금해집니다. 제 개인적인 생각으로는 폭발적인 인기는 없을 것 같습니다.

일단 기본 용도가 휴대폰인데 많은 사람들이 휴대폰을 선택할 때는 기능보다는 디자인, 유행, 가격등으로 선택하고, 기능도 카메라 화소수, 멀티미디어 플레이어, DMB등의 휴대폰에서 중요시 하는 기능만 보면 더 우수한 다른 휴대폰들이 많기 때문입니다.
(출처: apple)

맥과 모바일미, 아이튠즈와 같이 사용하지 않고, 컴퓨터를 사용할 때와 같이 사용자들의 노력이 없다면 아이폰의 장점은 '보는 사람마다 다른 주관적인 디자인'외에는 많지 않은 것 같습니다. 하지만 그 디자인과 OS X를 기반으로 한 여러 이점때문에 스마트폰으로서는 괜찮은 판매량을 보일 것 같습니다.

맥을 쓰는 사람 보다 나온지 얼마 안된 아이팟 터치를 쓰는 사람들이 훨씬 많은데, 아마 터치 보다는 많이 팔리지 않을까 하는 생각이 듭니다. 이런 마케팅, 비즈니스 쪽으로는 문외한이라 빨리 뚜껑을 열어 보고 결과를 확인할 날이 빨리 왔으면 좋겠습니다.
모든 댓글을 환영합니다. (욕설과 광고는 삭제합니다.)
  1. Favicon of http://fzud.tistory.com BlogIcon fzud 2008.09.19 13:36  댓글주소  수정/삭제  댓글쓰기

    RSS 리더에 등록해놓고 블로그 잘 구독중입니다~ 저는 일본에서 활동하는 개발자인데(맥과는 관계없고 웹,오픈쪽 개발자) 올해 4월 참을수 없는 뽐프로 맥북에어를 구입후에 아이폰까지 구입후에 맥환경에서 코코아 개발에 관심이 생겨서 이리저리 자료를 찾아다니면서 공부중입니다. c++은 학부때 해보고 건드려 본적이 없고 object c를 보니 이건 무슨 외계언어? 같은 심정인데 한국에도 관심있는 사람이 많아져서 많은 개발 자료를 공유할수 있으면 좋겠내요.

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

      아이폰 개발에 관심 있는 분들중에 일본에 계신는 분들이 많으시네요. 아마 관련 커뮤니티를 다니시다 보면 근처에 계시는 분들을 몇분 만나실 수 있을 것 같습니다.

      맥북에어+아이폰... 최고입니다. :)

  2. 지성공자 2008.09.19 14:43  댓글주소  수정/삭제  댓글쓰기

    언제 이런 멋진 포스트를 저도 블로그 하나 운영해야 할까봐여 너무 게을러서...

    한국에서 초기에는 많은 관심이 일듯한데 얼마나 갈지는 폰가격 대비 성능이 좌우하지 않을까 생각하고 있습니다. 국내 제조사들도 편의성과 국내특화를 무기로 달려들것이고 경재사들의 견제도 볼만할거 같구요. 현재 RIM의 블랙베리나 HTC의 스마트폰도 마켓쉐어를 나눠 갖기위해 경쟁하게 될것 같이고 세계최대 핸드폰 업체 노키아도 제품출시를 눈앞에 두고 있다죠? 더욱이 최대 라이벌 Android 도 나온다니... 선택의 폭이 넓어지고 고민도 쉽지 않아질거 같은데. 전 그래도 아이폰에 힘을 실어주고 싶네요.

    개발툴을 제공하는 핸드폰은 당분간 아이폰이 유일하겠죠? 기대합니다. ^^

    • Favicon of https://www.cocoadev.co.kr BlogIcon cocoadev 2008.09.20 01:55 신고  댓글주소  수정/삭제

      애고, 공자님이 여기까지 오셨네요. ^^;; 안드로이드도 SDK를 제공하는 것으로 알고 있습니다.

      이것 저것 많이 나와서 소비자들의 선택의 폭이 넓어 질 수록 좋은 거 겠죠. :)

  3. voiceman99 2008.09.20 02:06  댓글주소  수정/삭제  댓글쓰기

    항상 이곳에서 좋은 정보를 얻을수 있어 감사드립니다
    지금은 준비단계로 공부중인데 언제가는 맥에서 개발할 날이 오겠죠.
    많은 도움이 됩니다

  4. Favicon of http://www.juniac.net BlogIcon juniac 2008.09.22 15:06  댓글주소  수정/삭제  댓글쓰기

    항상 너무나 잘 보고 있습니다. ^^

  5. Favicon of http://kieuns.pe.kr BlogIcon 문기은 2009.03.02 14:46  댓글주소  수정/삭제  댓글쓰기

    일본에서는 일본 휴대폰 문화에 맞게 폰수정을 안해주는 바람에, 판매가 시들해졌습니다.
    요샌 거짐 공짜로 아이폰을 구할 수 있을만큼 가치가 하락해버렸구요. ( 아 초반에 구한 저는 덤탱이 쓴 느낌 ) 하지만, 아이포드터치 보급율이 높고 원래 맥용 개발자 풀이 많아서인지 소프트는 엄청 많이 나옵니다.
    한국도 많아지는걸 보니, 공부해두면 득이 될 것 같다는 느낌이..

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

      거의 공짜라니 부럽네요. 한국과 일본뿐만 아니라 여러국가에서 판매할 수 있으니 공부해 두시면 좋을 것 같습니다. :)



사용자 삽입 이미지
맥과는 달리 아이폰에서는 아이콘 파일(*.icns)을 사용하지 않고, 57X57 사이즈의 PNG 파일 포맷을 사용하는 것 같습니다.





사용자 삽입 이미지
재미있는 것은 좌측이 원본 아이콘 이미지이고 우측이 아이폰의 홈스크린에서 보여지는 모습입니다. 시스템에서 자동으로 아이콘의 모서리를 둥글게 보여주고 명함 효과를 주기 때문에 이미지에서 별도의 작업이 필요 없습니다.

사용자 삽입 이미지
만약 이미지에 배경이 없고 투명색으로 처리되었을 경우에는 좌측과 같이 검정색 배경의 아이폰 아이콘의 형식으로 출력이 됩니다.




* 아이콘 파일 등록
아이콘 파일은 메뉴의 'Project/Add to Project...'나 Groups & Files에서 해당 디렉토리를 우클릭 한 후에 아래와 '같이 Add/Exsiting Files...'를 클릭하여 해당 파일을 선택하시면 됩니다.

사용자 삽입 이미지


* 아이콘 파일 지정
사용자가 지정하지 않으면 실행파일 번들내의 Icon.png를 기본 아이콘 파일로 인식합니다. 별도로 아이콘 파일을 지정할 경우에는 Info.plist 또는 아래와 같이 타겟의 Info Properties의 'Icon File:' 항목에서 png 확장자를 제외한 파일명을 입력합니다. 

사용자 삽입 이미지
모든 댓글을 환영합니다. (욕설과 광고는 삭제합니다.)
  1. challenge 2008.09.11 17:01  댓글주소  수정/삭제  댓글쓰기

    이 홈페이지에서 여러 강좌 정말 잘 보고 갑니다.
    혹시 시간나시면 아이팟에서는 네트웍 프로그래밍을 어떻게 해야 하는지
    예제 좀 보여주실 수 있을까요? ^^;

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

      좋게 봐주셔서 감사합니다. :)

      네트워크쪽은 티돌이란 어플을 아이폰용으로 변환할려고 생각중이어서 염두에 두고 있었습니다. 기회가 되면 알아보고 관련된 글을 올려 보겠습니다.

  2. challenge 2008.09.12 11:46  댓글주소  수정/삭제  댓글쓰기

    정말 기대됩니다. 그런데 혹시
    제작하신 어플을.. 아이팟으로 옮기는 과정에 대해서 다루신 글이 있으신가요?
    지금까진 맥 상에서만 시뮬레이팅 해봤는데 아이팟 터치로도 옮겨서
    실제로 실행을 해보고 싶은데.. 절차를 모르겠네요 ㅠㅠ

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

      제가 아이팟 터치가 없습니다. ^^;; jailbreak된 터치에선 가능하다는 이야기를 들은 것 같은데, 저도 확실히는 모르겠네요.

  3. 서홍기 2008.09.12 19:24  댓글주소  수정/삭제  댓글쓰기

    와..정말 잘 보고 배워갑니다.
    뒤늦게 아이폰 개발툴에 대해 소식을 듣고 검색하면서 찾아왔네요.
    좋은 프로그래밍 강좌도 있고..
    자주 만나뵈러와야겟네요.

  4. Favicon of http://www.digist.co.kr BlogIcon 베니 2009.02.22 21:52  댓글주소  수정/삭제  댓글쓰기

    정말 도움 많이 됩니다. ^^ cocoadev님 홈페이지 RSS등록해서 매일 보고 있습니다. 좋은 글 많이 올려주세요.

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

      아고.. 부담이 됩니다. ^^; 요즘은 바쁘다는 핑계로 자주 올리지 못해 아쉽네요. 곧 많이 올릴 날이 왔으면 좋겠습니다. :)



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

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 클래스를 따로 사용하는 부분이 없기 때문에 헤더파일을 추가하지 않으셔도 될 것 같습니다.