iOS 2010. 4. 9. 15:56
어제 애플에서 아이폰 OS 4에 관련된 내용들을 발표했습니다. 직접 보지는 못하고 애플 사이트에서 iPhone OS 4 Event 키노트를 보았습니다.

예전 같으면 SDK 베타부터 다운로드 받아 설치했을 것 같은데 이제는 업무로 Xcode를 사용하다 보니 베타 버젼은 설치를 기피하게 되네요. 그런 변명도 있고 제가 가진 OS X가 10.5라 더이상 업그레이드를 할 수 없는 상태이기도 합니다. 맥북이라 느리기도 하고 조만간 아이맥을 구입해야 할 것 같습니다. 이젠 더 이상 손을 놓고 기다리기 힘들게 되었습니다.

맥의 OS X도 마찬가지지만 이번 아이폰 OS의 업그레이드 내용을 보면 'OS 업그레이드는 이렇게 하는 것이다'라는 전형적인 모범답안을 보여주고 있는 것 같습니다. 1.0부터 모든 버젼의  업그레이드를 이미 다 계획해 놓은 듯이 보여질 정도로 단계적으로 업그레이드를 해갈때 마다 완성형에 가까운 모습으로 가고 있는 것 같습니다.

이번 업그레이드도 많은 변경이 있지만 키노트에서는 아래와 같이 7가지 주요 기능을 위주로 설명하고 있습니다. 간단한 내용은 아래와 같습니다.

1. 멀티태스킹
오랫동안 논란이 되어왔던 멀티태스킹이 드디어 아이폰에서도 가능하게 되었습니다. 멀티태스킹은 하드웨어의 성능때문에 아이폰 3GS와 3세대 터치에서만 가능합니다.

2. 폴더
폴더를 만들어 비슷한 어플을 그룹화시켜 저장할 수 있습니다. 이로인해 기존 180개에서 2,160개까지 어플을 저장할 수 있게 되었습니다. 배경화면도 사용자가 지정한 이미지로 설정할 수 있게되었습니다.

3. 메일
메일함이 통합되고 메일을 스레드로 볼 수 있게 되었습니다. 또한 성능이 개선되고 첨부파일을 서드파티 어플에서 열어 볼 수 있습니다.

4. 아이북
아이패드에서 보았던 아이북이 아이폰에도 추가되었습니다.

5. 엔터프라이즈
데이터 보안이 강화되고 SSL VPN을 지원합니다. 데이터 보안 API는 일반 개발자들도 사용할 수 있습니다.  그리고 인하우스 앱들은 네트워크를 사용해 설치할 수 있습니다.

6. 게임센터
게임센터가 추가되었습니다. 친구를 초대하고 대전상대를 찾고 스코어가 기록됩니다.

7. 아이애드
iAd란 어플리케이션에서의 광고를 지원합니다. 이익의 60%가 어플리케이션 개발자에게 지급됩니다.

가장 큰 변경사항은 멀티태스킹입니다. 이로인해 어플리케이션이 백그라운드로 실행될 수 있기때문에 이와 관련된 메소드들이 많이 추가되었습니다. 백그라운드로 전환되어 대기상태가 될때는 OpenGL ES 메소드를 호출한다거나 네트워크을 사용하지 말아야하며 주소록 같은 시스템 리소스도 해제해야합니다. 많은 메모리를 사용하고 있다면 이역시 해제해야합니다.

만약 메모리와 같은 시스템 리소스가 부족하면 백그라운드에서 실행중인 어플리케이션이 먼저 제거대상이됩니다. 또한 시스템이 어플리케이션이 백그라운드로 전환될 때 메인윈도우를 캡쳐해 놓고 전환시 사용하기 때문에 패스워드같이 민감한 정보는 해당윈도우에서 삭제하길 권장하고 있습니다. 그리고 사용자 설정이 변경될 때 어플이 대응할 수 있도록 필요하다면 관련 통보 메시지를 처리해야 합니다. 이와함께 백그라운드에서 실행되는 어플들이 알려야할 내용이 있을때 사용할 수 있도록 위해 로컬 노티피케이션도 추가되었습니다.

Game Kit에는 게임센터를 지원하는 메소드들이 추가되었습니다. 애플에서 제공하는 서버와 서비스를 이용하여 사용자들의 점수를 저장할 수 있고 사용자들은 특정 사용자를 초대하거나 다른 사용자들을 선택할 수 있습니다.

이외에 어플리케이션에서도 SMS를 보내고 파일을 공유하고 PDF를 생성하고 사용자 폰트를 사용할 수 있는등 많은 기능과 서비스들이 추가되고 변경되었습니다. 애플에서 제공하는 iPhone OS 4 beta API Diffs란 문서를 참조하시면 4.0 SDK에서 추가된 내용들을 확인하실 수있습니다.

현재 애플의 기세는 MS, 구글, 아도비, 닌텐도, 소니등 모든 IT 업체들과 적이되어 홀홀 단신으로 싸울려는 모습으로 보여지기도 합니다. 이런 자신감은 수많은 어플리케이션을 올리며 든든히 뒤에는 바쳐주는 개발사와 개발자가 있기 때문이 아닌가라는 생각도 듭니다.

이번 SDK 4.0에서 추가된 많은 서비스와 API를 이용하여 지금과는 또다른 독특하고 재미있는 어플들이 많이 나올 것 같다는 생각이 듭니다.

'iOS' 카테고리의 다른 글

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
AND

얼마전 출판사에서 리뷰요청과 함께 책을 보내주어 아이폰과 안드로이드 관련 책을 받아 보았습니다. 마침 요즘 하고 있는 안드로이드 프로젝트 때문에 정신이 없어 이제서야 간단하게 나마 책에 대한 느낌을 올려 봅니다.

두권의 책은 일본서적을 번역한 것이라는 것과 초보자를 대상으로 하고 있다는 공통점을 가지고 있습니다. 안드로이드와 아이폰으로 나누어져 있다는 것만 제외하고는 편집상태도 그렇고 두책을 본 느낌은 거의 동일합니다. 이 두 책의 장점은 대상이 명확하다는 것입니다. 어느정도 익숙한 사람도 아닌 해당 플랫폼에 처음으로 입문하는 사람을 그 대상으로 하고 있습니다.

300페이지가 조금 넘어가는 부담없는 분량에 기본적으로 알아야할 내용들을 자세하게 설명하고 있습니다. 개발에 익숙하신 분들이면 하루 정도면 읽을 수있고 해당 플랫폼에서의 개발을 어느정도 이해하실 수 있습니다.

애플리케이션 개발자 안드로이드 매력에 빠지다
카테고리 컴퓨터/IT
지은이 HIDEO KINAMI (영진닷컴, 2010년)
상세보기
안드로이드 관련서적은 2개 정도 이미 가지고 있었습니다. 그 두책에 비해서 내용은 적지만 오히려 초반에 감을 익히기에는 이 책이 더 나았을 거란 생각이 들었습니다. 어차피 책은 처음에 개념만 익히는 것이고 실제 개발시에는 책보다는 대부분 관련 사이트의 레퍼런스를 많이 활용하게 됩니다.

내용은 쉽게 이해할 수 있도록 되어 있으나 오타들이 있는 것 같습니다. 100 페이지에 보면 아래와 같은 ImageView와 ImageButton의 속성을 정의하는 소스가 있습니다.

<ImageView
.. 중략 ..
android:text=@"android:drawable/ic_menu_help"/>

<ImageButton
.. 중략 ..
android:text="@android:drawable/btn_start_big_on"/>

ImageView, ImageButton 두 위젯 모두 'android:src'로 리소스를 지정하는데 'android:text'로 잘 못 지정되어 있습니다. btn_start_big_on도 btn_star_big_on로 변경되어야 하고요. 그외에 111 페이지에 있는 소스에서도 아래와 같은 이상한 내용의 소스가 있습니다.

<FrameLayout
<TableLayout
<FrameLayout
<LinearLayout
...중략...
>
<Chrometer
<Button
</LinearLayout>

붉은 색의 갑자기 나타나 닫히지도 않은 태그들은 아마 편집시 잘 못들어 온 것 같습니다. 현재까지 본 이 오타들은 처음 보는 분들에게는 혼란을 줄 수 있을고, 초보자를 대상으로 한 책에서 이런 오류는 아쉬운 부분입니다. 이런 오타에도 불구하고 누군가 안드로이드 입문서를 물어 본다면 이 책을 추천하겠습니다.

[2쇄 부터는 수정되어 인쇄되었다고 합니다]


애플리케이션 개발자 아이폰 매력에 빠지다
카테고리 컴퓨터/IT
지은이 KENGO TSURUZONO (영진닷컴, 2010년)
상세보기
이책 역시 처음 입문하는 분들을 대상으로 쉽고 친절하게 설명되어 있습니다. 광대한 범위를 다루고 있지는 않지만 아이폰 개발에 입문하기에 좋은 책으로 생각됩니다. 많은 이미지와 도표들이 있어 이해하기도 쉽습니다. 디자인적인 측면에서 읽기가 좀 불편하지 않나 하는 생각인데 이는 보는 사람들에게 따라 평가가 달라질 것 같습니다. 확인해 보니 원서와 같은 디자인인 것 같습니다.

위에서도 언급했듯이 두 책 다 제가 본 책중에선 가장 쉽게 초보자를 대상으로 잘 나온 책인 것 같습니다. 책은 아무래도 서점에서 직접 보고서 자신과 궁합이 맞는 것을 고르는 것이 가장 좋을 것 같습니다.

AND

여지껏 아이폰으로 잘 개발하고 있다가 오늘 Xcode를 실행해보니, 빌드가 안되는 것이었습니다. 빌드가 잘될 때랑 지금이랑 Xcode도 그렇고 아이폰도 그렇고 바뀐 것은 아무것도 없었습니다. 오거나이즈를 열어 보니 아래와 같은 메시지가 나타났습니다.


Provisioning과 Application 정보가 나와야 할 곳에 "Could not support developement"란 오류메시지가 보였습니다. "Xcode cannot find the software image to install this version"는 말그대로 Xcode가 인스톨할 새로운 OS 이미지가 없다는 것으로 이전부터 나온 메시지였습니다.

인터넷에서 검색을 해보기에 앞서 이전부터 뜬금없이 나오는 프로비저닝 오류에서도 리부팅을 하면 된적이 있어 리부팅을 해보았습니다. 결과는 성공이고 초록색불과 함께 정상적으로 기기를 사용할 수 있었습니다.

한번은 오거나이즈에서 "This device is not currently connected."란 메시지가 나왔습니다. 그때는 Xcode를 재실행하니까 되더군요. 우연인지 모르겠지만 터치로 개발할 때보다 아이폰으로 개발할 때 이런 일들이 더 자주 일어 나는 것 같습니다.

이유는 모릅니다만 "안되면 껐다 켜라"라는 컴퓨터 사용시의 진리가 아이폰과 터치에서도 통하는 것 같습니다.

'기타' 카테고리의 다른 글

세계지도 앱 - World Atlas  (2) 2010.04.21
모토로이  (6) 2010.02.11
아이폰 3GS  (2) 2009.09.17
블로그를 또 다시 이전했습니다.  (4) 2009.05.11
실버라이트2 동영상 재생 속도  (0) 2009.02.13
AND

기타 2009. 9. 17. 11:23
일때문에 아이폰 3GS를 잠시 가지고 있게 되었습니다. 다들 아시다시피 터치와 다른점은 조금 더 두껍고 카메라가 달렸다는 것입니다. 어플리케이션은 전화, 메시지와  나침반 정도가 눈에 뜁니다.

제가 만든 사전을 돌려보니 터치 2세대에서는 검색시 약간의 멈춤이 있었는데 3GS에서는 멈춤없이 바로 실행되더군요. 정확한 스펙은 보지 않았지만 속도도 많이 빨라진 것 같습니다.

전화는 개통되지 않았기 때문에 화면의 버튼들만 눌러 보았습니다. 제가 그동안 블랙잭만 써서 그런지 번호를 누르기가 정말 편하게 되어 있는 것 같았습니다.

카메라와 동영상의 화질도 블로그에 올리는 등 웹상에서 사용하기에 전혀 무리가 없을 정도로 괜찮았습니다. 혐오스러운 사진일 수도 있겠지만 3GS를 들고 다니며 찍은 사진이 없어 이것으로 올려 봅니다.


제 개인 블로그에는 주로 먹고 마시는 소소한 일상들을 많이 올리고 있습니다. 주로 블랙잭으로 많이 찍어 화질이 조금 아쉬웠는데 이정도면 괜찮을 것 같다는 생각이 듭니다. 한달전쯤 집사람의 핸드폰이 고장났습니다. 9월 초 아이폰이 나온다는 소문이 있어서, 아이의 핸드폰을 사용하며 기다려 보다가 출시되면 같이 아이폰을 사기로 했습니다.

늘 그렇듯이 역시나 잘못된 소문이었네요. 집사람은 다른 핸드폰을 사고 전 계속 아이폰을 기다리고 있습니다. 아이폰 하나면 되는데 항상 블랙잭과 터치, 두개를 가지고 다니기 번거롭고 빨리 나와주었으면 좋겠는데, 늘 소문만 무성하네요. 애플의 아이폰 발매 국가 페이지의 Coming Soon에 나오기전까지는 잊고 살자고 했는데, 막상 실제 아이폰을 보니 가지고 싶은 마음에 또 조급해집니다.

'기타' 카테고리의 다른 글

모토로이  (6) 2010.02.11
역시 그냥 껐다 키는 것이...  (8) 2009.09.24
블로그를 또 다시 이전했습니다.  (4) 2009.05.11
실버라이트2 동영상 재생 속도  (0) 2009.02.13
sqlite3 둘러보기  (3) 2009.02.02
AND

RSS를 읽어 오는 간단한 리더기를 만들어 보겠습니다. 맥에서는 NSXMLDocument란 편리한 클래스가 있지만 아이폰 SDK에는 포함되어 있지 않습니다. 그렇기 때문에 NSXMLParser를 사용해서 RSS xml을 읽어오는 간단한 샘플을 만들어 보겠습니다.

인터넷을 통해 데이터를 가져오는 부분은 이전  "NSURLConnection으로 웹페이지 내용 가져오기"란 포스팅을 참고 하시기 바랍니다. 여기서는 파싱하는 부분만 간단히 살펴보겠습니다.


1. NSXMLParser 생성
xml 데이터 파싱은 네트워크로 데이터 수신이 완료된 후 불려지는 connectionDidFinishLoading 메소드에서 아래와 같이 처리합니다.

NSXMLParser *parser = [[NSXMLParser alloc] initWithData:receiveData];

[parser setDelegate:self];
[parser parse];
[parser release];

NSXMLParser 오브젝트를 수신된 데이터가 저장된 NSData 타입의 receiveData를 인자로 초기화를 합니다. setDelegate 메소드로 현재 오브젝트를 NSXMLParser의 딜리케이트로 지정합니다. 지정된 오브젝트는 요소별로 파싱의 시작/종료와 파싱된 스트링을 받을 수 있는 메소드를 구현해야 합니다.

parse 메소드로 파싱이 시작됩니다. 파싱은 자동으로 처리되지 않으며, 각 단계별로 딜리게이트된 메소드를 구현하여 필요와 형식에 맞게 직접 처리해야 합니다.

2. Delegate 메소드 구현
NSXMLParser에는 많은 딜리게이트 메소드가 있지만 가장 중요하고 거의 반드시 구현해야될 메소드는 parser:didStartElement, parser:foundCharacters, parser:didEndElement입니다.

parser:didStartElement로 한 요소의 파싱이 시작됨을 알수 있습니다. parser:foundCharacters로 해당 문자열들이 넘어 옵니다. 토큰 단위로 넘어 오기 때문에 넘어 오는 문자열들을 계속 저장해야 합니다. parser:didEndElement가 실행되면 비로소 한 요소의 파싱이 끝난 것을 알 수 있습니다. 이 메소드에서 해당 요소에 따른 필요한 처리를 합니다.

1) 시작 메소드 구현
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
    if ([elementName isEqualToString:@"item"])
        elementType = etItem;
   
    [xmlValue setString:@""];
}

두번째 인자인 elementName으로 해당요소의 이름이 전달됩니다. 세번째와 네번째 인자는 네임스페이스와 관련된 uri와 전체이름이 전달됩니다. 만약 해당 xml이 네임스페이스를 사용한다면 이전에 [parser setShouldProcessNamespaces:YES];로 네임스페이스를 처리하도록 설정해야 합니다. NSXMLParser의 shouldProcessANamespace의 기본값은 NO 입니다.

마지막 인자인 attributeDict에는 해당 요소의 속성들이 전달됩니다. 만약 <item lang="ko"> 와 같이 되어 있다면 attributeDict 딕셔너리에 key가 'lang', value가 'ko'로 저장되어 전달됩니다.

여기서는 다른 인자들은 무시하고 item이란 이름의 요소가 시작될때 부터 데이터들을 저장하도록 요소이름이 item인지만 확인합니다. 그리고 xmlValue에 새로운 데이터를 저장하기 위해 이전에 저장된 값들을 초기화합니다.

2) 데이터 저장 메소드 구현
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    if (elementType == etItem) {
        [xmlValue appendString:string];
    }
}
토큰별로 넘어오는 문자열을 xmlValue에 저장합니다.

3) 종료 메소드 구현
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    if (elementType != etItem)
        return;

    if ([elementName isEqualToString:@"title"]) {
        [currectItem setValue:[NSString stringWithString:xmlValue] forKey:elementName];
    } else if ([elementName isEqualToString:@"link"]) {
        [currectItem setValue:[NSString stringWithString:xmlValue] forKey:elementName];
    } else if ([elementName isEqualToString:@"description"]) {
        [currectItem setValue:[NSString stringWithString:xmlValue] forKey:elementName];
    } else if ([elementName isEqualToString:@"category"]) {
        [currectItem setValue:[NSString stringWithString:xmlValue] forKey:elementName];
    } else if ([elementName isEqualToString:@"pubDate"]) {
        [currectItem setValue:[NSString stringWithString:xmlValue] forKey:elementName];
    } else if ([elementName isEqualToString:@"item"]) {
        [xmlParseData addObject:[NSDictionary dictionaryWithDictionary:currectItem]];
    }
}

한 요소가 끝날때 호출됩니다. 여기서는 RSS의 title, link, description, category, pubData 항목들만 currentItem 딕셔너리에 저장합니다. 한 포스팅의 마지막 요소인 </item>일 경우에는 xmlParseData에 현재 딕셔너리를 추가합니다.

3. 테이블뷰 출력
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [xmlParseData count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
   
    static NSString *CellIdentifier = @"Cell";
   
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }
   
    NSDictionary *dict = [xmlParseData objectAtIndex:indexPath.row];
    [[cell textLabel] setText:[dict objectForKey:@"title"]];
   
    return cell;
}

여기서 테이블뷰는 아무 동작을 하지않으며 xmlParseData에 저장된 해당 title만 출력합니다. 빌드 후 실행하면 아래와 같이 해당 RSS의 제목이 출력되는 것을 확인할 수 있습니다.

간단한 RSS 리더기를 구현해 보았습니다. 전체 소스는 아래의 압축파일을 다운로드 받아 확인하실 수 있습니다. 정확하고 자세한 내용은 아이폰 개발자 센터에서 제공하는 Introduction to Event-Driven XML Programming Guide for Cocoa 문서 또는 SeismicXML 샘플코드를 확인하시기 바랍니다.

'iOS' 카테고리의 다른 글

아이폰 OS 4  (8) 2010.04.09
인터페이스빌더 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
AND

발표전에 한국출시가 거의 확실시되던 분위기가 있어 이번에는 많은 기대를 가졌습니다. 하지만 아쉽게도 한국에서 출시한다는 소식은 없었습니다. 2년반정도를 기다리고 있는데 도대체 얼마를 더 기다려야 정말로 나오는 건지 답답합니다.

터치가 있지만 아이폰을 간절히 바라는 이유는 카메라로 찍어서 바로 블로그나 다른 서비스들에 글과 사진을 바로 올릴 수 있고, 터치와 함께 늘 핸드폰도 같이 챙겨야 하는 불편함도 없앨수 있기 때문입니다. 제 맘대로 되는 것이 아니니 그냥 신경을 끊고 또 기다려 봐야죠.

어제 애플 사이트에서 WWDC 키노트가 공개되어 보았습니다. 이미 관련된 내용들을 보았고 개발자 사이트에선 대부분 공개된 내용이지만, 스노우 레오퍼드와 아이폰 OS 3.0 소개하는 부분이 재미있었습니다.  스노우 레오퍼드는 64bit 지원, GCD, OPenCL 기술을 강조하더군요. 그외에 새로운 퀵타임 X와 MS의 익스체인지 서버 지원등의 내용이 있었습니다.

(이미지 출처: 애플 키노트)

사용자 입장에서 스노우 레오퍼드의 업그레이드 주내용이 성능향상에 있다는 것이 매우 반가운 소식입니다. 게다사 설치용량은  오히려 줄었다고 하더군요. 집에 오래된 초기 인텔 맥미니가 하나 있는데 설치가 가능할 것 같다는 생각이 듭니다.

아이폰 OS 3.0의 업글레이드 부분도 이미 개발자 사이트에선 공개된 내용이지만 이를 활용한 몇가지 실제 적용된 어플들을 볼 수 있어 좋았습니다. 3.0의 새로운 기능들로 인해 본격적으로 아이폰의 진수를 보여주는 어플들이 많이 나올 것 같다는 생각이 들었습니다.

스노우 레오퍼드도 그렇고 아이폰 OS 3.0도 그렇고 애플의 업그레이들은 처음부터 모든 것이 다 계획되어 있던 것이 아닌가 하는 착각이 들정도로 업그레이드 전략이 예술인 것 같습니다. 실제 다 계획되어 있는 것인지도 모르겠습니다.

(이미지 출처: 애플 키노트)

마지막으로 이전 아이폰보다 2배 빨라지고 300만 화소의 카메라, 동영상 촬영, 음성명령이 가능한 아이폰 3Gs에 대한 소개가 있었는데 그야말로 그림의 떡이었습니다. 잊고 지내다 보면 언젠가는 나오겠죠. 휴~

AND

아이폰 해상도에 맞는 간단한 동영상 플레이어를 만들어 보았습니다. 유튜브등 기존 동영상 서비스를 이용하는 것에 비해 자체 서버 또는 호스팅이 필요하고 트래픽에 대한 부담감이 있지만 아이폰 해상도에 최적화된 선명한 시연 동영상을 보여줄 수 있는 장점이 있습니다. 만약 트래픽이 부담이 될 정도면 그 어플은 흔히 말하는 대박이라고 보아야 겠죠. ^^;


동영상은 320X480의 wmv 포맷을 지원합니다. 저는 iShowU HD란 프로그램으로 시뮬레이터를 캡쳐한 후에 (위 동영상은 가로방향이 조금 틀렸습니다) MPEG Streamclip을 이용하여 wmv로 변환하였습니다. ISPlayer.xap를 다운로드 후에 웹서버에 올려놓고 아래와 같이 HTML 스크립트를 추가하시면 됩니다. 시간나는데로 플렉스 버젼도 올릴려고 합니다.

<object width="340" height="635" data="data:application/x-silverlight-2," type="application/x-silverlight-2" style='z-index:1;'>
<param name="source" value="ISPlayer.xap URL"/>
<param name="initParams" value="movie_url=WMV 동영상 URL"/>
<a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration: none;">
<img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/></a>
</object>


AND

애플의 App 스토어와 아이폰/아이팟 터치에 관심을 가지시는 분들이 많아지면서, 아이폰 개발을 어떻게 시작 하는지 궁금해 하시는 분들이 계셔서 이에 관해서 포스팅을 해볼려고 합니다. 개발에 관한 직접적이거나 기술적인 이야기 보다는 준비해야 할 것, 관련 사이트/서적등에 대해 간단히 써보겠습니다.

기존에 다른 플랫폼에서 개발경험이 있는 분들은 조금만 자료를 찾아 보시면 쉽게 적응을 할 수 있으시니, 이 글에서는 별다른 도움이나 흥미있는 내용이 없을 것입니다. 이 포스팅은 아래와 같은 분들을 대상으로 합니다.

  • 애플 제품을 사용해 본적이 없으신 분
  • 개발 경험이 없으신 분
  • 아이폰 개발을 시작하시려는 분
 
이번과 다음 포스팅에서는 아이폰 어플리케이션 개발을 위해서는 필요한 하드웨어와 소프트웨어에 대해서 알아 보겠습니다. 설명이 길지만 요점은 아래와 같습니다.
* 필수 사항
  • OS X 10.5* 설치된 Mac
  • ADC 회원 가입
  • Xcode
  • iPhone SDK

* 선택 사항
  • 아이팟 터치 (또는 아이폰)
  • 아이폰 개발자 프로그램 가입

1. 하드웨어
1)  Mac 컴퓨터
아이폰 어플리케이션은 Xcode 3( +  iPhone SDK)를 사용하여 개발합니다. Xcode 3.* 버젼과 iPhone SDK는 OS X 10.5(레오퍼드) 이상에서만 설치하고 사용하실 수 있습니다.

그렇기 때문에 레오퍼드가 설치되어 있는 하드웨어가 필요하고, 공식적으로는 애플에서 판매하는 맥을 구입하셔야 합니다. (해킨토시나 cygwin에서 툴체인을 사용하는 방법은 논외로 하겠습니다.) OS X 10.5 레오퍼드에 대해서는 애플의 개발자를 위한 Leopard 기술이란 문서를 참조하시기 바랍니다.

 
1.1) 사양 비교
한국 애플스토어에서 판매하는 맥의 종류와 가격은 아래와 같습니다. 아쉽게도 요즘 환율로 인하여 최근에 나온 맥들은 이전보다 사양에 비해 가격이 많이 상승했습니다.


제품의 사양 및 평가는 제 경험에 의한 지극히 주관적인 평가입니다. 절대적인 것이 아니니 참고만 하시기 바랍니다.

* 맥미니
맥미니 1.83GHz은 가장 저렴한 맥으로 69만원이며, 현재 판매되는 맥중에서 성능은 가장 낮습니다. 또한 맥미니는 디스플레이와 키보드/마우스가 포함되어 있지 않기 때문에, 추가로 구입을 하거나 미리 준비가 되어 있어야 합니다. 하지만

(저는 집에서 가장 사양이 낮은 맥 미니 1.83GHz를 사용하고 있지만, Xcode에서 아이폰 어플리케이션을 개발하고 시뮬레이터를 실행하는데 전혀 부족함을 느끼지 못했습니다. 하지만 리소르를 많이 사용하는 작업이나 고사양의 3D 게임과 같은경우에는 부족한 점이 느껴질 것 같습니다.)


*
iMac

iMac은 디스플레이와 키보드/마우스가 제품에 포함되어 있기 때문에, 추가비용이 거의 발생하지 않습니다. 가격대 성능비가 가장 우수한 맥입니다. 개인적으론 개발용으로 사용하기에는 iMac이 비용대비로 가장 적당하지 않나 생각됩니다. iMac은 외부 모니터도 사용가능하기 때문에, iMac 디스플레이까지 포함하여 듀얼 모니터로 사용할 수 있습니다. 하지만 별도의 Mini DVI to VGA 또는 Mini DVI to DVI 어댑터를 구입하셔야 합니다.


*
맥북/맥북 프로/맥북 에어

당연한 이야기지만 가장 무난한 것은 맥북, 이동성 위주로 선택하면 에어, 성능 위주로 선택하면 맥북 프로입니다. 컴퓨터를 들고 다녀야 할 일이 없다면 개발이나 다른 용도로도 iMac이 더 나은 것 같습니다. 하지만 맥이 2대가 아니면서 집이외에 사무실/학교 등에서도 맥이 필요할 시에는 가장 좋은 선택으로 생각됩니다.

(저는 사무실에서 이전 세대의 2.4GB 흰색 맥북을 사용하고 있습니다. 구입시에 새로나온 iMac이 듀얼 모니터를 지원하는 것을 모르고, 이동할 일은 없지만 단순히 듀얼로 사용할려고 맥북을 구입했습니다. 제가 게임을 안해서 그런지 개발, 업무 및 일반적인 메인 컴퓨터로 사용시에도 사양이 떨어 진다는 생각은 전혀 들지 않았습니다.)


*
맥 프로

사용은 못 해보았지만 당연히 좋을 것 같습니다. 최저사양의 본체 가격만 315만원이며 맥 프로답게 강력하게 사용할려면 메모리와 하드 용량을 더 추가하면 기하급수적으로 비싸집니다. 능력이 되시는 분들은 당연히 맥 프로가 좋습니다.

(제게 있어서는 꿈의 하드웨어이고 다음 세대 iMac이 나오면 맥북에서 갈아 탈려고 합니다. 그리고 3년 정도 더 사용하다 맥 프로를 써보는 것이 야심찬(?) 저의 계획입니다.)


사양이 좋고 속도가 빠르면 빠를 수록 좋지만 가격을 감안하여 용도, 사용 장소, 휴대 여부등을 고려하여 결정하시면 될 것 같습니다. 위에도 언급하였지만 가장 사양이 낮은 맥미니도 아이폰 어플리케이션 개발을 위해선 무리가 없는 사양으로 생각됩니다.

1.2) 할인 혜택
* 교육 할인
대학생 또는 대학생 자녀를 둔 학부모와 유치원/초/중/고/대학교에 근무하는 교직원들은 교육할인 혜택으로 보다 저렴하게 맥을 구입할 수 있습니다.

* 구제품 할인
애플의 할인 스토어에서 구제품을 구입하는 방법도 있습니다. 애플인증 구제품은 반품제품을 애플에서 다시 수리, 교체하여 테스트 후에 판매하는 제품입니다. 거의(?) 새제품을 할인된 가격에 구입할 수 있습니다. 하지만 재고가 많지 않아 등록되자 마자 빠르게 팔리기 때문에 항상 확인을 해야 합니다.

* 중고 직거래
kmug와 같은 관련 커뮤니티 사이트들의 장터를 이용해 직접 중고 맥을 구입할 수 있습니다. OS X 10.5가 설치되어 있거나 설치가 가능하며 인텔 프로세스를 사용한 맥으로 구입하시면 됩니다.


2) 아이팟 터치
아이폰 어플리케이션은 아이폰과 아이팟 터치에서 실행됩니다. 아쉽게도 아이폰은 현재 우리나라에서 판매되지 않기때문에, 외국에서 따로 구입하지 않는다면 아이팟 터치가 거의 유일한 선택입니다.

아이팟 터치는 현재 2세대 제품이 판매되고 있습니다. 1세대와의 기능상 차이점은 아래와 같습니다. Xcode의 시뮬레이터가 있기 때문에 개발시에 아이팟 터치가 반드시 있어야 하는 것은 아닙니다. 배포를 생각하지 않고 있고 터치가 필요하지 않다면 시뮬레이터로도 개발은 가능합니다.

  • 스피커 내장
  • Nike+ 내장
  • 배터리 사용시간 증가
  • 음량 조절 버튼 추가

아이팟 터치는 저장 용량에 따라 8GB, 16GB, 32GB로 판매되고 있으며, 각각의 가격은 아래와 같습니다.

* 8GB - 280,000원
* 16GB - 370,000원
* 32GB - 489,000원

터치는 위의 용량에서 시스템이 1GB정도를 사용하고 있습니다. 역시 용량이 많을 수록 좋겠지만 사용계획과 가격에 따라 적당한 용량을 선택하시면 됩니다. 저는 8GB이며 몇개의 동영상, 노래 30여곡, 어플리케이션, pdf파일, 그림 파일등을 넣고 다니는데 현재 1GB 정도사용하고 있으며 6GB가 사용가능한 용량으로 남아 있습니다.

아이폰 개발시 필요한 하드웨어에 대해서 간단히 둘러 보았습니다. 다음 포스팅에서는 필요한 소프트웨어와 ADC 멤버 프로그램과 아이폰 개발자 프로그램에 대해서 알아 보겠습니다.
 * 관련링크
iPhone 어플리케이션 개발을 위한 준비 - 1. 하드웨어
iPhone 어플리케이션 개발을 위한 준비 - 2. 소프트웨어
iPhone 어플리케이션 개발을 위한 준비 - 3. 관련 자료
iPhone 어플리케이션 개발을 위한 준비 - 4. 시작하기

AND

몇일 전 아마존에서 도서 추천 메일을 받았습니다. 맥과 아이폰 프로그래밍에 관련해서 나온 신간들인데, 대부분 아직 출시는 되지 않았고 예약을 받고 있었습니다. 새로 나올 관련 도서와 저자들을 대충 보면 아래와 같습니다.

Core Animation for Mac OS X and the iPhone
- $23.07
- Pragmatic Bookshelf
- Bill Dudney
- 188page

저자는 iPhone SDK Development의 공동저자중 한사람인 Bill Dudney입니다. 소개하는 책중에서 유일하게 아마존에서 현재 판매중인 책입니다. 페이지도 얼마 안되고 내년 초쯤에 구입해 볼까 생각중입니다.


RubyCocoa
- $23.07
- Pragmatic Bookshelf
- Brian Marick
- 300page

이전에 한번 제 블로그에서도 포스팅 했었던 RubyCocoa에 관련된 서적이 나올 예정에 있습니다. Brian Matrick은 애자일 방법론 컨설던트이며, Kent Beck, Andrew Hunt등과 함께 애자일 선언서의 작성자중 한명입니다. 이런 주제의 책이 벌써 나올 수 있다는 것이 신기하고 부럽기도 합니다.


iPhone SDK Application Development
- $23.09
- O'Reilly Media, Inc.
- Jonathan Zdiarski
- 250page

오렐리에서 나오는 대부분의 아이폰 개발 서적을 쓴 Jonathan Zdziarski의 신간입니다. 책 제목과 표지를 봐서는 아이폰 SDK의 교과서적인 책이 아닐까 생각됩니다.


Learn Objective–C on the Mac
- $26.39
- Apress
- Mark Dalrymple, Scott Knaster
- 350page

우리나라에 OS X 프로그래밍 서적중 유일하게 번역되어 나온 코코아 프로그래밍의 원저자인 Aaron Hillegass의 Big Nerd Ranch에서 근무하고, Advanced Mac OS X Programming 의 공동저자인 Mark Dalrymple의 신간입니다. Scott Knaster는  Hacking Mac OS X TigerMacintosh Programming Secrets의 저자이며 현재 구글의 애플팀에서 근무하고 있다고 합니다.

이와 비슷하게 아래의 Dave Mark가 쓴 Learn Cocoa on the Mac도 출간을 앞두고 있습니다.


Beginning iPhone Development
- $26.39
- Apress
- Dave Mark , Jeff LaMarche
- 536page

90년대 초 파스칼과 C의 맥 프로그래밍 관련 서적을 쓴 오래된 맥 프로그래밍 저자인 Dave Mark와  iphonedevelopment 블로그 운영자인 역시나 경험 많은 개발자인 Jeff LaMarche가 쓴 책입니다.


iPhone in Action
- $26.39
- Manning Publication
- Christopher Allen, Shannon Appelcline
- 350page

iphonewebdev.com의 운영자인 Chritopher Allen과 게임 RPG 시나리오 작가인 Shannon Appelcline이 공저로 아이폰 어플리케이션에 관한 내용도 있지만, 아이폰에 적합한 웹 사이트를 만드는데 치중한 책인 것 같습니다.


iPhone Programmer's Road Map
- $26.39
- Addison-Wesley Professional
- Michael Juntao Yuan, Sam Griffith, Norm Richards
- 288page

Cocoa와 Objective-C, 모바일 프로그래밍의 전문가들이 공동으로 집필한 책입니다. 아이폰 개발에 관한 전반적인 내용을 다루고 있는 것 같습니다.

(이미지 출처:아마존)



코코아 프로그래밍, 특히 아이폰 개발에 관한 책들이 다수 나오고 있습니다. 출판사 사이트들을 들어가 보면 이외에도 준비하고 있는 책들이 많이 있었습니다. 아직은 원서로 밖에 볼 수 없는 것이 아쉽기도 하고 이중 몇개의 책들이 번역이 되서 나올지 모르겠네요.

아직 사놓고 못 읽은 책들이 많아 올해에 깨끗이 마무리하고, 내년초에 흥미있어 보이는 책들을 주문해 보아야 겠습니다. 

AND

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

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

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

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

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

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


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

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

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

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

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

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

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

맥을 쓰는 사람 보다 나온지 얼마 안된 아이팟 터치를 쓰는 사람들이 훨씬 많은데, 아마 터치 보다는 많이 팔리지 않을까 하는 생각이 듭니다. 이런 마케팅, 비즈니스 쪽으로는 문외한이라 빨리 뚜껑을 열어 보고 결과를 확인할 날이 빨리 왔으면 좋겠습니다.
AND

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





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

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




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

사용자 삽입 이미지


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

사용자 삽입 이미지
AND

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

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



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

AND

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

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

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

간단하게 아이폰용 바이오리듬 어플리케이션을 만들어 보겠습니다. 저도 처음 아이폰 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들이 멋있어서 맞출려면 디자인이나 이미지에 신경을 써야 할 것 같습니다. 나중에 조금 더 알아본 후에 월별로 출력하도록 수정하고 몇가지 변경해 본 후에 다시 한번 올려 보겠습니다.
AND

오늘 모바일미를 신청하고 가입했습니다. 어제 가입할려고 했는데 아래와 같은 메시지가 출력되면서 가입을 할 수 없었습니다. 가는 날이 장날이라고 정기점검 시간이었나 봅니다. 메시지가 영어, 독일어, 스페인어, 일어인 것 같은데 맞는지는 모르겠습니다. 늘 느끼는 것이지만 아시아에서는 역시 일본이 애플로 부터 대접을 받네요.

사용자 삽입 이미지

현재 모바일미는 60일 무료 트라이얼로 사용할 수 있습니다. 이 기간내에 서비스 해지를 하지 않으면, 가입시에 입력한 신용카드로 매년 미화로 99달러를 지불하는 것 같습니다. 99달러의 기본 서비스는 총 20GB의 용량하며 메일저장 공간으로 10GB, iDsik에서 10GB의 공간을 사용할 수 있습니다.
사용자 삽입 이미지
149달러의 Family Pack은 20GB의 저장공간에 네명까지 아이디를 제공 받아 사용할 수 있습니다. 각자 5GB씩 사용할 수 있는데 용량이 조금 부족해 보입니다. 기본 용량에서 49달러를 내면 20GB를 99달러는 40GB를 추가로 구입할 수 있습니다.

입력정보와 신용카드 정보를 입력하고 가입을 완료하면 아래와 같은 메시지가 출력됩니다.
사용자 삽입 이미지

맥과 아이폰/터치는 당연한 것이고, 간단한 설명을 보니 아마 PC의 아웃룩과도 동기화가 되는 것 같습니다. 'Mac setup'을 클릭해서 들어가 설명대로 시스템 환경설정으로 가보니 닷맥 아이콘이 있었습니다. 혹시나 해서 소프트웨어 업데이트를 해보니 아래와 같은 업데이트 내역이 있었습니다.

사용자 삽입 이미지

사용자 삽입 이미지
제가 업데이트 주기를 너무 길게 해놔서 그런 것 같습니다. '매일' 확인으로 변경했습니다.

업데이트가 되고 맥이 리부팅 된 후에 다시보니 이쁜 'MobileMe' 아이콘으로 변경되어 있었습니다. (이 부분은 제가 착각한 것 같습니다. 집에 와서 해보니 시스템 설정에서 닷맥을 클릭하고 로그인 하니 업데이트가 진행되었습니다.)

아래와 같이 집에 있는 맥과 동기화할 항목을 설정하고 '지금 동기화'를 클릭했습니다. 이제 양쪽에서 '캘린더'와 '연락처'가 동기화 해서 사용할 수 있다는 것이 가장 편리한 것 같습니다.
사용자 삽입 이미지
맥에서 설정을 완료하고 www.me.com 사이트로 갔습니다. 역시 애플의 제품들과 일괄적인 사이트의 디자인이 이쁘네요.
사용자 삽입 이미지

사용자 삽입 이미지
로그인을 하면 좌측 상단에 모바일미의 기능을 요약해 주는 아이콘들을 볼 수 있습니다. 좌측부터 차례대로 메일, 주소록, 일정, 겔러리, iDisk, 계정설정 아이콘입니다. 각각의 기능들은 아래와 같습니다.


1. 메일
메일로 가보니 환영메일이 한통 와 있었습니다. 각 폴더로 항목들의 드래그엔드랍이 가능하기 때문에 웹상에서의 사용도 그다지 불편한 점이 없습니다. 첨부파일은 20MB까지 가능하며, 기본으로 10GB의 메일 저장 공간이 할당됩니다. 메일 주소는 '[아이디]@me.com'으로 사용할 수 있습니다.

지인에게만 주는 개인명함이 있는데 지메일 주소를 넣었습니다. 미리 나왔다면 모바일미 주소를 사용하였을텐데 아쉽습니다.
사용자 삽입 이미지

한글이 깨지는 것을 방지하기 위해 아래와 같이 'Encode outgoing messages using Unicode (UTF-8)' 항목에 체크를 해주셔야 합니다.
사용자 삽입 이미지

2. 연락처
사용자 삽입 이미지
좌측은 제 맥과 동기화가 된 연락처의 화면입니다. 웹에서도 설정에서 성과 이름의 순서를 변경 옵션이 있어 우리나라의 '성 이름'과 같은 순으로 출력할 수 있습니다.

아주 잠깐 써보았지만 속도이외에는 웹 플랫폼이란 불편함이 그다지 느껴지지 않았습니다. 항목을 드래그앤드랍으로 해당 분류에 저장할 수 있고, 분류에서 클릭이나 엔터를 치면 바로 이름을 변경할 수 있습니다.

아래가 연락처 입력화면입니다. 맥에서와 같이 연락처의 종류도 설정할 수 있고, 입력 필드도 화면에서 바로 추가할 수 있습니다.
사용자 삽입 이미지

3. iCal - 일정관리
사용자 삽입 이미지
역시 웹상에서도 맥과 거의 동일한 인터페이스를 제공합니다. 시간대와 날짜에서 더블클릭을 하면 맥과 동일하게 바로 입력이 가능합니다. 키보드의 delete키로 바로 삭제도 가능하고, 역시 드래그엔드랍으로 원하는 위치로 이동이 가능합니다. 웹상에서 이렇게 자연스럽고 부드럽게 맥과 비슷한 인터페이스를 제공하는 것이 놀랍습니다.

4. 겔러리
사용자 삽입 이미지
겔러리에서 직접 이미지를 선택해서 올리거나 iPhoto 하단에서 업로드 할 이미지를 선택하고 '웹 겔러리' 버튼을 클릭하면 자동으로 겔러리에 선택한 이미지들이 등록 됩니다.

이미지가 등록되면 리로드 없이 바로 모바일미의 겔러리에 반영이 됩니다. 이미지를 회전하거나 크기를 조절할 수 있는 슬라이더등이 있습니다.
사용자 삽입 이미지

위 이미지의 우측의 URL은 해당 앨범의 URL이며 브라우져에서 주소를 직접 입력하면 아래와 같이 보여집니다. 동호회 모임등의 사진들은 앨범을 따로 만들어 참가자들에게 주소를 알려 주면 편리하게 사진을 감상할 수 있을 것 같습니다.
사용자 삽입 이미지

5. iDisk

iDisk는 기본 10GB를 사용할 수 있는 웹하드입니다. 집과 사무실에서 작업하기 위해 파일을 메일로 보내거나 USB메모리를 이용했는데, 이제는 간단하게 파일을 공유하여 사용할 수 있을 것 같습니다. 아래는 테스트로 제 맥에 있는 파일 하나를 업로드한 후의 모습입니다.
사용자 삽입 이미지

파인더에서도 내장된 하드와 동일하게 사용할 수 있습니다.
사용자 삽입 이미지

또한 주소는 idisk.ma.com/[아이디]-Public의 주소로 웹을 통해 다른사람들과 공유도 가능합니다.
사용자 삽입 이미지

신청하고 잠깐 살펴 보았는데 1년에 12만원 정도를 투자하는 것이 아깝지 않을 만큼 멋진 기능이 많은 것 같습니다. 아쉬운 것은 모바일미라는 이름답게 아이폰이 있어야만 모바일미를 진정으로 이용할 수 있다는 것입니다. 아이폰에서 모바일미의 사용은 생각만 해도 기대가 부풀어 오릅니다. 제발 좀 빨리 나와주었으면 하는 바램입니다.

'기타' 카테고리의 다른 글

레밍스와 유사한 게임 - Pingus  (6) 2008.07.23
PC vs 맥 vs 우분투의 재미있는 이미지  (10) 2008.07.22
스크래치 사이트 한글화  (0) 2008.07.02
각 언어별 Hello World 출력  (0) 2008.05.08
OS X 코드명과 동물이름  (10) 2008.04.22
AND

인터넷에서 새로나온 아이폰 3G가 우리나라에서도 시판된다는 소문을 듣고 이번 WWDC에 많은 기대를 하고 있었습니다. 하지만 오늘 아침 소식을 들으니 아직 한국에서 판매는 결정되지 않았더군요. 애플 사이트에 키노트가 올라와서 슥슥 넘겨가면서 대충 보았습니다. 아래의 화면에서 경쾌한 음악과 함께 아이폰이 출시되는 70여개의 국가들이 하나하나 소개되었는데 한국은 없었습니다.

사용자 삽입 이미지

너무나 기대하고 있던 제품이기에 실망스럽고 허탈하고 화가 나네요. 애플에 실망해야 할지, 위피를 의무화한 정부에 실망 해야 할지, 이동통신사에 실망해야 할지 모르겠습니다. 오늘 새벽 WWDC를 지켜보지 않고 과음으로 잠들어 버린 제 죄입니다. 하지만 언젠가는 출시될 것으로 기대하고 있습니다. 차기 3G 아이폰중 가장 궁금했던 것은 가격이었는데 199달러라니 다소 의외면서도 그나마 반가운 소식입니다.

사용자 삽입 이미지
이전 포스트
에서 OS X 차기 버젼의 코드명이 궁금하다는 이야기를 한적이 있었는데, 애플 사이트를 가보니 'Snow Leopard'인 것 같습니다. 번역하면 설표인가요? Snow가 들어 가니 내년 겨울에 나오는 것이 어울릴 것 같습니다.

아직 개발중이라 그런지 배경화면도 레오퍼드와 같고, 사용자 입장에서는 눈에뛰는 커다란 변화는 없는 것 같습니다. 'Core innovation'을 내세우는 것을 보니 이번 버젼에서는 성능, 안정성등 눈에 보이지 않는 부분에 주력하는 것 같기도 합니다.

아이폰으로 맥라이프의 화룡점정을 찍을려고 하는데 기다리는 시간이 너무 기네요. 조만간 한국에서도 아이폰이 출시된다는 좋은 소식이 들리기를 바랍니다. 수입하지 않았으면 하는 것은 잘도 수입되는데 간절히 바라는 것은 수입이 안되네요. ^^;

'이야기들 > 소소한 이야기' 카테고리의 다른 글

Tumblebugs 드디어 클리어!  (2) 2008.06.18
맥북 DVI 어댑터  (2) 2008.06.16
맥세이프 전원 아답터  (6) 2008.05.20
요즘 근황...  (2) 2008.05.19
맥북을 구입했습니다  (8) 2008.05.14
AND

iOS 2008. 5. 26. 14:05
사용자 삽입 이미지
어제 iPhone SDK를 다운로드 받고 설치를 해보았습니다. SDK는 애플의 다운로드 페이지에서 받으실 수 있습니다. 실행환경은 OS X 10.5.2 이상의 인텔맥에서만 사용할 수 있습니다. 최신 버젼은 2008년 5월 8일에 올라 왔으며 파일크기가 1GB가 조금 넘었습니다.

 Xcode 3과 레오퍼드의 개발툴들을 잘 몰라서 설치 후 무엇이 추가되고 변경되었는지는 잘 모르겠습니다. 다만 Xcode와 Dashcode에서 차이점을 발견할 수 있었습니다.

1. Xcode
그러고 보니 아직 Xcode 3에서 한번도 New Project를 실행해 본적이 없었습니다. 그렇지만 아래의 iPhone OS란 메뉴가 SDK 설치로 새로 생겼을 것으로 짐작은 됩니다.

사용자 삽입 이미지

이름을 보니까 아이폰 SDK에서 사용하는 Cocoa는 'Cocoa Touch'로 부르는 것 같습니다. 일단 'Cocoa Touch Application'을 선택하고 프로젝트를 만들어 보았습니다.

사용자 삽입 이미지
프로젝트 명을 'iPhoneSDK'로 하였더니 좌측과 같은 파일들이 기본적으로 생성되었습니다.
 
기존 Cocoa 프로젝트에서 볼 수 있었던 파일들도 보이고 iPhoneSDKAppDelegate 클래스와 MainWindow.xib와 몇개의 프레임워크등 새로 추가된 부분들도 보입니다.

NIB Files가 비어 있어 순간 인터페이스빌더를 지원하지 않는가 생각했는데 MainWindow.xib를 더블클릭하니 인터페이스 빌더를 볼 수 있었습니다. nib의 n이 NeXTSTEP을 의미하는 것으로 알고 있는데 xib의 x가 OS X를 의미하는지는 모르겠습니다. (나중에 OS X 어플리케이션으로 만들어 봐도 nib 파일 대신 xib가 생겼습니다. 이 부분은 Xcode 3에서 변경된 것 같습니다.)

사용자 삽입 이미지
   
우측에 생략된 전체 이름은 'I PhoneSDK App Delegate' 입니다. 

사용자 삽입 이미지
라이브러리 팔레트에서는 좌측과 같이 사용할 수 있는 오브젝트나 컨트롤들의 목록이 있습니다. 이전에 아이폰의 사진에서 보았던 버튼이나 UI들도 보입니다.

몇개 끌고 와서 윈도우에 배치를 해 보았습니다. 실제 구현은 아직 모르기 때문에 무조건 빌드를 하고 실행을 해 보았습니다.





사용자 삽입 이미지
특이하게 애플은 일반적으로 사용하는 에뮬레이터가 아니라 시뮬레이터라고 이름을 붙였습니다. 아이폰 시뮬레이터를 살펴 보는데 아직 베타 버젼이라 그런지 제가 잘 못 해서 그런지 실행된 어플리케이션의 입력란에 포커스가 갈 경우에는 시뮬레이터가 다운되었습니다. 


아래의  좌측은 인터페이스 빌더에서 작업한 모습이고 우측은 빌드 후에 아이폰 시뮬레이터에서 실행된 모습니다.

사용자 삽입 이미지

자동으로 생성된 코드들은 아래와 같습니다. main에 추가 된것은 UIApplicationMain에 대한 호출입니다. 실제 작업은 그 이름과 같이 AppDelegate 클래스에서 수행해야 하는 것 같습니다. 아마 UIKit이 아이폰의 핵심 프래임워크 같습니다.

main.m
#import <UIKit/UIKit.h>

int main(int argc, char *argv[]) {
   
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, nil);
    [pool release];
    return retVal;
}

iPhoneSDKAppDelegate.h
#import <UIKit/UIKit.h>

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

@property (nonatomic, retain) UIWindow *window;

@end

iPhoneSDKAppDelegate.m
#import "iPhoneSDKAppDelegate.h"

@implementation iPhoneSDKAppDelegate
@synthesize window;

- (void)applicationDidFinishLaunching:(UIApplication *)application {   
    // Override point for customization after app launch
}

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

@end


2. Dashcode
혹시나 하는 마음에 Dashcode도 실행해 보았습니다. 아래와 같이 New Project에서 Web Application이란 추가된 항목이 있었습니다.

사용자 삽입 이미지

이전 포스팅에서 한번 보았던 RSS를 선택하고 새 프로젝트를 만들었습니다. 이전과 동일하게 속성의 Feed URL에 올블로그 주소만 입력하고 실행해 보았습니다. 아래와 같이 시뮬레이터가 실행되었습니다.

사용자 삽입 이미지
아마 Dashcode로 만든 어플리케이션은 사파리내에서 실행되는 거 같습니다. 웹어플리케이션이니까 당연히 웹플랫폼에서 실행되겠지만 주소창이나 브라우져의 UI들은 안 보여 줄 것으로 생각했는데 아닌 것 같습니다.

아직 Xcode 3도 모르고 간만 본 상태에서 조금 이른 생각 같지만 iPhone에서의 개발은 기존의 다른 모바일 플랫폼 보다 쉬운 것 같습니다. 신경써야 될 폰이 아이폰 딱 하나인 것도 개발자 입장에선 편할 것 같고요. 개발자료들도 ADC에 충분한 것 같으니 많은 어플리케이션들이 나올 것 같습니다.
SDK와 툴들을 대충 둘러 보면서 느낀 첫번째 생각은 우리나라에 나오기만 하면 꼭 아이폰을 사야 겠다는 것이었습니다. 비록 에뮬 환경에서 일부분만 본 아이폰이지만 화면과 UI가 환상이었습니다. 에뮬레이터로 핸드폰 뽐뿌 받기는 처음이었습니다.
AND

iOS 2008. 3. 8. 09:35
어제 애플에서 아이폰의 SDK를 공개하고 로드맵을 발표했습니다. 발표후 아이폰 소프트웨어 로드맵을 알리는 애플의 메인화면뿐만 아니라 ADC의 메인 화면도 아이폰과 맥 개발로 양분된 모습을 보니 애플이 아이폰 어플리케이션 개발에 얼마나 많이 기대를 하고 신경을 쓰고 있는지 짐작할 수 있습니다.

사용자 삽입 이미지

아래는 발표 동영상중에서 몇가지 게임 시연 모습을 캡쳐한 이미지들입니다. 3D 슈팅게임에서는 아이폰을 움직이며 비행기를 조종하고 화면을 터치해 발사하는 모습이 재미있었습니다.
사용자 삽입 이미지 사용자 삽입 이미지 사용자 삽입 이미지

기억나는 것은 이미지를 편집하다 아이폰을 좌우로 흔들면 실행이 취소(Undo)되는 모습이었습니다. 별다른 버튼이 없는 아이폰이기 때문에 Undo를 실행할 수 있는 방법이 그것밖에 없을 것도 같지만 매우 인상적이었습니다. (휴~ 이 동영상을 보니 아이팟 터치에 대한 구매의욕을 겨우 잠재워 놨는데 이제 더이상 견딜 수 없게 된 것 같습니다)

한가지 흥미로운 부분은 어플리케이션 만들어 애플의 App 스토어에 등록하면, 사용자들은 아이폰이나 터치로 인터넷을 통해 App 스토어에서 필요한 어플리케이션을 검색하고 구매할 수 있습니다. 이로 인해 수익이 일어 날 경우 금액의 70%를 제작자가 받을 수 있다고 합니다.

소프트웨어를 제작만 하면 애플이 유통을 담당해주니 좋은 어플리케이션을 개발만 할 수 있다면 개인 개발자들도 수익을 올릴 수 있을 것 같습니다.

하지만 개발자가 위의 서비스를 이용할려면 아이폰 개발자 프로그램에 등록해야 하는 것 같습니다. 등록비용은 개인을 대상으로 한 Standard는 99달러, 기업을 대상으로 한 Enterprise는 299달러입니다. 현재는 미국의 개발자들만 등록할 수 있는 것 같습니다. 몇달안으로 다른 여러 나라로 확대된다고 합니다.

SDK는 아이폰 DevCenter에서 다운로드 받으실 수 있으며 크기는 2.1GB입니다. 홈페이지에는 벌써 개발에 필요한 많은 레퍼런스와 샘플코드, 강좌 동영상들의 자료들이 충분히 준비되어 있습니다. 바로 시작할 수 있습니다.

그러나!!!

사용자 삽입 이미지

"OS X 10.5(레퍼드)는 언제 써볼수 있을까..." 라면 촐싹대는 것이 아니였는데...
AND