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


동영상은 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

이전에 만들었던 스모킹 카운터의 소스를 복사해서 간단한 카운팅 어플을 만들어서 앱스토어에 등록했습니다. 어제 저녁에 올렸으니 아직 리뷰중입니다. 판매의 의도 보다는 cocos2d나 한번 써볼려고 만든 어플인데 디자인만 입혀서 올려 보았습니다.

+ 버튼을 눌러 어떤 행동에 대한 카운팅을 하는것이 주목적이고 카운팅 숫자 만큼 돼지가 화면에 나타납니다. 드래그할 수 있고 높은 곳에서 떨어뜨릴 수가 있고 해를 눌러 정렬, 렌덤, 점프등 간단한 명령을 내릴 수 있습니다. 그외에 시간 간격이나 일/월/년별 통계를 볼 수 있고요. 하지만 별 쓸데가 없는 어플이라 저도 안쓸 것 같습니다.

사실은 이것보다 아이폰 어플 소개를 위한 동영상 플레이어를 만들어 보고 싶은데요. 아래와 같이 대부분의 플레이어는 가로로 보여주기 때문에 제대로 보이지 않기 때문에, 어플 고유의 해상도로 아이폰 스킨을 적용한 플레이어를 만들어 볼려고 생각하고 있습니다. 게을러서 늘 마음만 먹고 있었지만 일단 어플을 올렸으니 리뷰까지 7~10일정도내에는 만들겠죠.



저도 공부도 할겸 테스트용으로 만들은 소스지만 UI, cocos2d, sqlite3등 처음하시는 분들에게 도움이 될수도 있을 것 같아 공개하기로 했습니다. 역시나 급조한 소스라 부끄럽긴 하지만 취미로 쉬엄쉬엄 하는 cocoa 프로그래밍에 익숙해져 그나마 덜 부끄럽게 소스를 공개하기는 하세월일 것 같아 그냥 감행했습니다.

별것 아닌 소스지만 아래의 사항은 꼭 지켜주셨으면 좋겠습니다.

  • 이미지 파일과 디자인은 테스트 용도 이외에는 사용하실 수 없습니다.
  • 소스는 어떠한 제약도 없으며 디자인만 변경하여 Action Counter Pro로 올리셔도 상관 없습니다.
  • 소스파일은 퍼가거나 링크를 하실 수는 없습니다.
  • 저도 도움이 되고 다른 분들도 알아야 되니 오류가 있을경우 알려 주시면 감사하겠습니다.
  • 소스에 대한 질문과 설계, 네이밍등 코드에 관한 논평은 받지 않겠습니다. 저도 알고 있으니 그냥 삭제하시기 바랍니다.

아래는 프로젝트를 압축한 파일이며 다운로드 받으셔서 사용하시면 됩니다. cocos2d 링크가 제 환경으로 되어 있으니 이 부분은 각자의 환경에 맞게 수정하셔서 빌드하시면 될 것 같습니다. cocos2d 설정은 제 이전 포스트를 참고하시고요.



'App Store' 카테고리의 다른 글

앱스토어에 대한 소고 - 2  (10) 2009.05.09
사전 어플리케이션  (0) 2009.05.01
스모킹 카운터 1.2 버그  (0) 2009.03.18
Smoking Counter 등록 완료  (64) 2009.03.03
제 계정으로 처음 어플리케이션을 등록했습니다  (28) 2009.02.26
AND

iOS 2009. 4. 13. 10:59
cocos2d-iphone 는 OpenGL ES를 기반으로 하는 게임, 에니메이션, 데모등을 위한 2D 라이브러리입니다. 기본적인 에니메이션부터 메뉴, 스코어 서버까지 지원하기 때문에 빠른 시간에 편리하게 사용할 수 있습니다. cocos2d-iphone 사이트에서 최신 버젼을 다운로드 받으실 수 있습니다.



1. cocos2d 설정
1) 빌드
다운로드를 받으신 후에 압축을 풀고 Xcode Project 파일을 클릭하여 Xcode를 실행합니다. Active Target을 cocos2d로 하고 Actvie SDK를 Device로 빌드 합니다.


Active SDK를 Simulator로 하고 다시 한번 빌드합니다.


cocos2d는 프로젝트 자체에 여러 샘플소스들을 많이 가지고 있습니다. Target을 해당 데모로 변경하여 실행을 확인해 보실 수 있습니다.

2) 라이브러리 복사
해당 폴더의 빌드 폴더를 보시면 2개의폴더에 각각 libcocos2d.a와 libChipmunk.a가 같이 빌드되어 있습니다.


원하시는 곳에 폴더를 만드시고 이 두 폴더의 파일들을 각각 다른 폴더로 가져다 놓습니다. 저는 /Developer/Library 밑에 Cocos2d란 폴더를 만들고 그 밑에 Device와 Simulator 폴더를 만들어 각각의 라이브러리 파일들을 가져다 놓았습니다.

3) 헤더파일 복사
/Developer/Library/Cocos2d 밑에 헤더파일들을 복사하기 위해 Include 폴더를 새로 만듭니다. Include 폴더의 하위로 Support 폴더를 만듭니다. 다시 cocos2d 폴더로 와서 보시면 하위에 똑 같은 이름의 cocos2d란 폴더가 있습니다. 이 폴더내의 *.h을 위에서 생성한 Include 폴더로 복사합니다. 하위의 Support 폴더내의 *.h 파일도 해당 폴더의 Support 폴더내로 복사합니다. (파인더에서 정렬을 종류로 하시면 헤더파일별로 쉽게 가져 올 수 있습니다.)


그리고 cocos2d 폴더의 external/Chipmunk/src에 있는 *.h 파일도 위와 같이 생성한 Include 폴더로 복사합니다. Chipmunk는 게임등에 사용되는 물리엔진으로 컴파일을 위해 헤더파일이 꼭 필요하며 실제 사용하지 않을 경우에는 라이브러리는 추가하지 않으셔도 됩니다.

4) fps_images.png 복사
cocos2d가 초당 프레임수를 출력할 때 사용하는 이미지를 해당 프로젝트의 Resource 폴더에 복사해 놓으셔야 됩니다. 이 이미지가 없을 경우에는 아래와 같은 실행오류가 발생합니다.


cocos2d 폴더의 Resources/Images에 있는 fps_images.png 파일을 적당한 위치에 복사해 놓습니다.



2. Xcode 설정
Xcode에서 New Project를 클릭하여 iPhone OS/Application의 Window-Based Application으로 프로젝트를 생성합니다. 프로젝트명을 cocos2d App로 입력합니다.

1) Search Paths 설정
좌측과 같이 Groups & Files에서 프로젝트를 우클릭한 후에 Get Info를 클릭하여 Project 정보창을 오픈합니다.

두번째 Build에서 Search Paths항목에서 Header와 Library를 각각 해당 폴더로 입력합니다.

아래와 같이 Header Search Paths, Library Search Paths가 입력되어 있는 것을 확인합니다.

2) cocos2d 라이브러리 링크
Linking 항목중 OPther Linker Flags에 -lcocos2d를 입력합니다.


libcocos2d.a를 드래그 해서 직접 추가하여 사용하셔도 됩니다. 하지만 시뮬레이터와 디바이스의 선택에 따라 각각의 라이브러리 파일이 필요하기 때문에 Active SDK가 변경될 경우에는 매번 파일을 변경해 주어야 합니다.

그렇기 때문에 설정에서 Configuration이 Debug일때는 Library Search Paths를 Simulator로 Release일 때는 Device로 설정합니다. 시뮬레이터로 개발시에는 Debug 모드로 개발하고 실제 기기에서 테스트시나 업로드시에는 Release 모드를 선택하면 해당 라이브러리 파일의 변경없이 편하게 사용하실 수 있습니다.

3) 프레임워크 추가
cocos2d가 사용하는 OpenGL ES, QuartzCore 프레임워크를 추가합니다. 좌측과 같이 cocos2d App 타겟에 우클릭하여 Get Info를 클릭합니다.



General 항목의 좌측 하단에 [+] 버튼을 클릭합니다.
아래와 같이 OpenGLES.framework와 QuartzCore.framework를 선택하고 Add를 클릭합니다.


4) fps_images.png 추가
좌측과 같이 이전에 복사해 두었던 fps_images.png를 Resources 항목으로 드래그해서 가져다 놓습니다.



5) 프로젝트 템플릿 추가
cocos2d를 사용할 때마다 매번 위의 설정을 하는 것은 번거로운 작업입니다. 그렇기 때문에 기본설정된 항목을 템플릿에 추가하여 사용하는 것이 편리합니다. cocos2d App 프로젝트 폴더를  /Library/Application Support/Deveoper/Shared/Xcode/Project Templates/ 밑에 Application 폴더를 만드시고 그 아래에 복사합니다.
이제 새 프로젝트를 선택하면 User Templates/Application에 cocos2d App 항목이 나오며 위에서 cocos2d를 위해 설정된 사항대로 편리하게 사용하실 수 있습니다.

cocos2d에 관한 자세한 내용과 자료는 cocos2d-iphone 사이트에서 확인하실 수 있습니다.

'iOS' 카테고리의 다른 글

NSXMLParser로 RSS 읽어오기  (21) 2009.08.05
인터페이스빌더 Table View Cell 사용하기  (0) 2009.06.25
iPhone SDK 3.0 beta 2  (4) 2009.04.05
UITableView의 메모리 누수 현상  (4) 2009.02.05
UIView에서 텍스트 출력  (10) 2009.01.13
AND

iOS 2009. 4. 5. 16:59
몇일 전 메일로 아이폰 SDK 3 베타가 나왔다는 소식을 들었는데 이제서야 추가되고 변경된 내용들을 개략적으로 둘러 보았습니다. 중요한 변경사항으로는 블루투스를 공식적으로 지원하며 30핀 독 컨넥터를 이용해 각종 액세서리들과 통신할 수 있는 수단을 제공하는 것과 App 자체내에서 결제를 제공하는 것 같습니다. 그외 각종 API가 추가되고 간단하게 사용할 수 있도록 변경되었습니다.
사용자 삽입 이미지
(이미지 출처: 애플)

애플 아이폰 개발자 센터의 아이폰 OS 3.0 소개 페이지에서 내세우는 6개의 큰 변화된 내용은 아래와 같습니다.

* In App Purchase
어플리케이션 자체내에서 사용자가 결제를 할 수 있는 StoreKit이란 프레임워크가 추가되었습니다. 이를 이용하면 App내에서 컨텐츠나 기능을 추가할 때 사용자로 부터 과금을 할 수가 있습니다. App는 무료로 배포하고 컨텐츠 접근시에만 유료로 결제를 받는 서비스들도 많이 등장할 것 같다는 생각이 듭니다. (델피니님이 댓글로 안된다고 말씀해 주셨네요. 제 착오 였습니다. ^^;;)

* Peer to Peer Connectivity
블루투스를 이용해 페어링 없이 아이폰(터치)간에 연결이 가능합니다. 이를 이용하여 데이터를 주고 받을 수도 있으며, 특별히 음성데이터를 위한 GKVoiceChatService란 서비스도 제공합니다. 연결될 기기를 선택하기 위한 기본적인 UI도 제공합니다.

* Apple Push Notification service
App가 실행되지 않을 때라도 Push Notification Service에 동록된 서버로 부터 메시지를 받을 수 있가 있습니다. App가 실행되지 않을 때 이 메시지를 받게되면 다이알로그박스, 뱃지, 효과음등을 통하여 사용자에게 새로운 데이터나 변경된 내역이 있다는 것을 알려 줍니다. 만약 어플리케이션이 실행중이라면 미리 정의된 메소드에서 이 메시지를 처리할 수 있습니다.

* Maps
구글 모바일 맵 서비스와 연동하는 Map View가 추가되었습니다. 확대, 축소가 가능하며 핀을 사용할 수 있고, 현제 좌표를 주소로 변환해주는 API도 제공합니다. 구글맵의 Open API를 사용하지 않고도 편리하게 관련된 어플리케이션을 만들 수 있습니다.


* Accessories

30핀 독과 블루투스를 통하여 외부 기기들과 통신할 수 있는  악세서리 API를 제공합니다. 아이팟의 악세서리와 이와 연동할 수 있는 App를 이용하여 다양하고 재미있는 악세서리들과 App들이 많이 나올 것으로 기대가 됩니다.

* iPod Library Access

사용자의 아이폰/터치에 있는 음악과 Podcasts, Audio Books, 플레이 리스트에 접근할 수 있는 API를 제공하면, 선택을 위한 기본적인 UI 컨트롤러도 제공합니다.

* 기타
이외에도 Cut, Copy & Paste를 지원하고, App내에서 이메일 발송을 위한 API와 UI를 제공하는 등 많은 변화가 있는 것 같습니다.

그리고 맥의 spotlight와 같은 검색기능이 추가되었습니다. 주소록, 미디어 파일등을 검색하는 용도로 사용하는 것 같습니다.


3.0에서 업그레이드 된 기능들을 이용해 개발사들은 더욱 다양한 수익모델을 만들 수 있을 것 같습니다. 사용자들도 다양한 악세사리들과 이와 연동되는 App를 사용할 수 있다는 것은 환영할 만한 일이라고 생각됩니다. 애플이 아이폰 SDK 업그레이드 로드맵을 장기적인 안목으로 정말 잘 짜놓은 것 같습니다.

AND

저번 주에 1.2 버젼을 올렸습니다. 통계에 섬머타임이 적용된 버그등을 수정하고 캐릭터 에니메이션을 추가하고 디자인을 조금 변경하였습니다.

어제 1.2 버젼이 리뷰를 끝내고 배포가 되었습니다. 그런데 어플 업로드시 공식 사이트로 등록해 놓은 블로그에 아이팟 터치 1세대 사용자께서 어플리케이션이 멈춘다는 글을 보았습니다. 혹시나 해서 앱스토어를 가보니 업그레이드 후 튕긴다는 리뷰를 보았습니다. 일단 더 이상 다운로드되는 것을 막기위해 스토어에서 내렸습니다.

제가 파악한 범위에서는 1세대 사용자에게서 문제가 발생하는데, 제가 1세대가 없고 늦은 시간이였기 때문에, 1세대를 가지고 있는 지인에게 연락하여 다음날 가져와 달라고 요청했습니다. 원인은 늘 그렇듯이 어처구니 없는 실수였습니다.

sqlite3_finalize(statement);
sqlite3_finalize(statement);

디버깅 하다보니 위와 같은 코드가 있더군요. 아마 복사를 하다 필요없는 sqlite3_finalize까지 같이 가지고 왔나 봅니다. 이 치명적인 오류는 해킹된 아이팟 1세대만 튕기고 나머지 시뮬레이터나 2세대에서는 견딘 것 같습니다.

두번째 어플리케이션이 멈추는 듯한 문제는 지나치게 느려진 속도에 있었습니다. 메인화면은 2개의 View로 나누어 놓았습니다. 상단은 에니메이션이 필요하고 추후에 다양한 에니메이션을 보여 주기위해 Open GL ES를 사용하기 위함이고, 하단의 수량, 시간등을 보여 주는 부분은 매 프레임 마다 에니메이션이 필요 없기 때문이었습니다. 그런데 이번에 업글을 하면서 하단의 뷰도 매 프레임 실행되도록 변경했습니다. 제 2세대에서는 아무 차이가 없었기 때문이었습니다. 하지만 1세대에서는 속도에 심각한 문제가 발생했습니다. 아마 애플도 리뷰시 2시대만 사용하는 것 같습니다.

현재는 이미지 출력시에 가장 간단한 방법인 drawAtPoint를 사용하고 있었습니다. 애니메이션이 더 추가되고 GL로 가기전에 그나마 퍼포먼스가 조금 나은 CGContextDrawImage로 교체할려고 합니다.

아무튼 오류를 고치고 그날 핀 수량을 뱃지로 보여주는 부분을 추가하여 다시 올렸습니다. 아마 다음주 초쯤 올라갈 것 같네요. 사용하고 계신분들께는 너무 죄송합니다.
AND

오늘 애플로 부터 등록이 심사가 완료되고 Ready fro Sale로 상태가 변경되었다고 메일이 왔습니다. 2월 25일에 올렸으니 심사에 6일정도 걸린 것 같습니다.

본업에 매달리는라 개발자 등록부터 늦게 했지만, 처음부터 시작해서 마지막 과정까지 경험해본 것 자체에 만족하고 있습니다.

사실 처음부터 과정을 정리해서 블로그에 올려 보고 싶었는데, 대부분 따라 해보다 안되고 다시 해보다 얼떨결에 된 경우들이 많아 정리도 안되고 저도 정확히 모르겠네요.

유료로 0.99달러에 올렸는데 블로그를 통하여 프로모션코드를 배포합니다. 프로모션 코드는 앱스토어의 미국계정에서만 사용할 수 있으니, 미국계정이 있으신 분들만 사용하실 수 있습니다. 비공개 댓글로 메일 주소를 알려 주시면 20분에게 프로모션 코드를 보내 드리겠습니다.

AND

어플리케이션을 만들어 다른 계정으로 앱스토어에 등록한 적은 있지만, 제 계정으로는 처음 등록해 보는 어플리케이션입니다. 어제 등록을 했으니 다음 주쯤이면 결과가 나올 것 같습니다.

담배피는 횟수를 체크해 주는 간단한 어플리케이션입니다. 하루에 담배를 2갑 정도 피우는 제 자신을 위해 이전부터 만들어 보고 싶었던 것이었습니다. 그동안 블로그도 못할 정도로 바빠서 늘 생각만 하고 있다가, 몇일전 시간을 내어 만들어 보았습니다.


흡연횟수가 늘어 날수록 캐릭터가 점점 망가지다가 설정한 목표를 넘어설 때 부터는 폐인 양이 되어 버립니다. 둥둥 떠다리는 + 버튼을 클릭하면 갯수가 늘어나며 간단한 에니메션이 있습니다.

사용자 삽입 이미지

통계에서는 시간/일/월/년별 통계를 볼 수 있도록 하였습니다. 알콜카운터도 만들어 볼려고 했는데 세면서 마시면 술 맛이 안날까봐 그만두었습니다.

'App Store' 카테고리의 다른 글

사전 어플리케이션  (0) 2009.05.01
아이폰 App - Action Counter  (26) 2009.04.30
스모킹 카운터 1.2 버그  (0) 2009.03.18
Smoking Counter 등록 완료  (64) 2009.03.03
10,000개 다다른 애플 App 스토어의 어플리케이션  (2) 2008.12.01
AND

이 부분에 대해서 방법을 찾고 있는데 현재는 미디어 플레이어의 rate를 설정하는 것처럼 실버라이트2에선 재생 속도를 변경하는 방법이 없는 것 같습니다. 꽁수로 재생시간을 조금씩 더 해보았는데 자연스럽지 않고 소리가 끊기면서 나와 옛날 비디오의 빨리감기를 보는 정도까지만 가능했습니다. 아래는 관련부분 소스입니다.

static double TIMER_INTERVAL = 300;
static double MOVE_MSECONDS = 10000;
static int MOVE_FF = 1;
static int MOVE_RW = -1;

public Page()
{
   
    /** 타이머 설정 */
    timerStoryboard.BeginTime = TimeSpan.Zero;
    timerStoryboard.Duration = new Duration(TimeSpan.FromMilliseconds(TIMER_INTERVAL));
    timerStoryboard.Completed += new EventHandler(timerCompleted);
}

private void ChangeSpeed()
{
    if (playSpeed == 0)
        return;

    double currentPos = mediaPlayer.Position.TotalMilliseconds;
    double newPos = currentPos + (MOVE_MSECONDS * playSpeed);
    double maxPos = mediaPlayer.NaturalDuration.TimeSpan.TotalMilliseconds;
    double downloadPos = Math.Floor(mediaPlayer.DownloadProgress * maxPos);

    mediaPlayer.Pause();
    
    /* 유효범위 검사 */
    if (newPos >= 0 && newPos < downloadPos)
    {
        mediaPlayer.Position = TimeSpan.FromMilliseconds(newPos);
        mediaPlayer.Play();

        timerStoryboard.Begin();
    }
    else
    {
        playSpeed = 0;
    }
}

private void timerCompleted(object sender, EventArgs e)
{
    ChangeSpeed();
}

/** 뒤로보기 클릭 */
private void btnRewind_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    playSpeed = MOVE_RW;
    ChangeSpeed();
}

/** 빨리보기 클릭 */
private void btnFast_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    playSpeed = MOVE_FF;
    ChangeSpeed();
}

ChangeSpeed()에서 mediaPlayer.Pause()와 mediaPlayer.Play()를 하지않고 빨리보기를 하면  어느정도 괜찮게 보이지만 역시 소리 부분은 부드럽게 재생이 안되네요. Position을 다시 설정하는 부분에 부하가 있어 밀리세컨드 단위의 세세한 제어는 힘든 것 같습니다. 또한 Progressive Download가 아닌 Streaming일 경우에는 저 방법으로는 대책이 없습니다. 저만 방법을 모르고 삽질중이라는 불길한 예감도 듭니다. ㅠㅠ

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

아이폰 3GS  (2) 2009.09.17
블로그를 또 다시 이전했습니다.  (4) 2009.05.11
sqlite3 둘러보기  (3) 2009.02.02
버그추적 시스템 Mantis 설치  (6) 2009.01.07
애플스크립트(AppleScript) 둘러보기  (5) 2009.01.06
AND

TableView 사용시 NSIndexPath에서 불특정하게 Instruments에서 메모리 누수가 감지되고는 합니다. 이전에도 이런 현상을 간혹 보기는 했지만, 혼자서 만들어 본 간단한 샘플이고 Instruments에 익숙하지 안다는 이유로 궁금증을 뒤로 하고 그냥 넘어 갔었습니다.


하지만 이번에 앱스토어에 올릴 어플리케이션을 준비하면서 또 위와 같은 문제를 만났습니다. 이번에는 그냥 넘어 갈 문제가 아니기 때문에 누수를 찾을려고 해보았습니다. 그러나 역시 찾지 못했습니다. 검색을 해보아도 비슷한 경우를 겪은 사람들은 많지만 딱히 해답은 없었습니다.

애플의 SimpleDrillDown이나 UICatalog와 같은 TableView를 사용하는 샘플에서도 이와 같은 누수가 감지됩니다. 애플의 담당자들도 실수를 할 수 있겠지만 이런 UI의 대표적인 샘플에서 정말 문제가 있었다면, 이에 관련된 업데이트가 그동안 있었을 것이라 생각이 됩니다.

또한 실제 디바이스에서 테스트를 하면 위와 같은 누수는 발생하지 않습니다. 이번에 2.2.1로 업그레이되면서 혹시나 해결되었나 했는데 마찬가지였습니다. 애플의 이에대한 공식적인 언급은 못보았지만, 잠정적으로 시뮬레이터의 버그이고 실제로 사용시에는 문제가 없다는 결론을 내렸습니다. 하지만 아직도 제가 무엇을 잘 못한 것은 아닌지 찜찜한 마음은 가시지 않네요. 혹시 원인이나 해결책을 아시는 분이 계신가요?

'iOS' 카테고리의 다른 글

cocos2d 개발환경 설정  (24) 2009.04.13
iPhone SDK 3.0 beta 2  (4) 2009.04.05
UIView에서 텍스트 출력  (10) 2009.01.13
iPhone 어플리케이션 개발을 위한 준비 - 4. 시작하기  (16) 2008.12.22
아이폰 SQLite3 샘플  (5) 2008.11.25
AND

기타 2009. 2. 2. 14:03
iPhone SDK를 사용하면서 데이터베이스로는 내장된 sqlite3를 조금 사용해 보았습니다. ruby on rails나 이전에 조금 본적은 있지만, 실제로 사용하다 보니 기존의 일반적인인 데이터베이스에 비해 몇가지 재미있고 색다른 부분이 있는 것 같습니다.

1. 특징 & 둘러보기
1) ROWID
SQLite3의 테이블등은 생성시 기본적으로 rowid란 칼럼을 가지고 있습니다. auto increment되는 primary key와 같은 역활을 하지만 vacuum에 의해 변경될 수가 있다고 하니, 이런 용도로는 테이블의 특성에 맞게 사용해야 될 것 같습니다.


select *로는 rowid가 출력되지 않고 명시를 해주어야지 값을 확인할 수있습니다. 마지막으로 인서트된 항목의 rowid는 sqlite3_last_insert_rowid 함수의 반환값으로 확인할 수 있습니다.

2) 데이터 타입
타입이 컬럼에 일괄적으로 적용되는 다른 데이터베이스와는 달리 sqlite3는 각각의 로우별로 동적으로 타입이 결정됩니다. 그렇기 때문에 칼럼타입에 어떤 문자를 주던지 혹은 생략하더라도 테이블 생성이 가능합니다. 아래와 같이 테이블을 만든 후에 어떤 타입의 값들을 넣더라도 모두 저장이 가능합니다.


아래와 같이 각 컬럼의 값들에 따라 데이터타입이 결정됩니다.


한 컬럼에는 기본으로 1GB까지 저장이 가능하며 컴파일시에 SQLITE_MAX_LENGTH 값을 설정하여 2GB까지 가능합니다. 하지만 이전에 간단히 테스트를 해보았는데 OS X에서는 3MB 정도까지만 가능했습니다. 아마 애플에서 제한크기를 낮추어 설치하지 않았나 짐작을 하고 있습니다. 리눅스에서는 몇 백MB까지 인서트가 가능했습니다.

2. 기본 명령어
1) 시작
sqlite는 파일을 기반으로 한 컴팩트한 DB입니다. 대부분의 DB들이 파일을 기반으로 하지만 sqlite3는 데이터베이스 오픈시 인자로 파일을 받습니다.

> sqlite3 [file-name]
파일이 존재할 경우에는 기존 db파일을 열고 존재하지 않을 경우에는 새로 생성합니다. 쉘에서는 쿼리와 구별하여 명령어에 '.'이 접두사로 사용됩니다.

2) 종료
.quit 또는 .exit는 sqlite3를 종료하는 명령어입니다.
sqlite3>.quit
sqlite3>.exit

3) 도움말
sqlite3>.help
sqlite3 쉘에서 사용가능한 명령어들을 보여 줍니다.

4) 테이블 목록
sqlite3>.tables
현재 데이터베이스에 등록된 테이블들의 목록을 확인할 수 있습니다.

5) 스키마 정보
sqlite3>.schema [table-name]
지정된 테이블의 스키마를 확인할 수 있습니다. 테이블명을 입력하지 않으면 모든 테이블의 스키마가 출력됩니다. "ALTER TABLE"도 있는데 add와 rename만 가능한 것 같습니다.

6) 쿼리결과를 파일로 저장
sqlite3>.mode insert
sqlite3>.output db.sql
sqlite3>select * from mytable;
sqlite3>.quit
mode는 출력될 타입을 지정하며 csv, column, html, insert, line, list, tabs, tcl등으로 설정할 수 있습니다. output은 저장될 파일을 지정합니다. 위와 같이 실행 후 종료하면 mytable의 데이터들이 insert로된 sql문으로 db.sql 파일로 저장되어 있습니다.

7) 테이블 변경
sqlite3>alter table [table_name] rename to [new_table_name];
sqlite3>alter table [table_name] add [new_column_name];
alter는 테이블명의 변경과 테이블 컬럼의 추가만 가능한 것 같습니다.

8) vacuum
sqlite3>vacuum
데이터베이스의 테이블의 로우를 재정렬하고 delete, drop으로 인한 빈공간을 제거하는 최적화 작업을 수행합니다. insert, delete, drop등의 명령을 자주 수행하는 DB들은 정기적으로 vacuum을 실행해 주는 것이 좋습니다.

3. 자주 사용되는 C 함수
1) Open & Close
int sqlite3_open(const char *filename, sqlite3 **ppDb);
int sqlite3_close(sqlite3 *pDb);

sqlite3 데이터베이스 파일을 열고 닫는 함수 입니다.

사용 예)
sqlite3 *db;
NSString* path = @"./mydb.sqlite3";

if (sqlite3_open([path UTF8String], &db) != SQLITE_OK)
    NSLog(@"Fail to open sqlite3: %s", sqlite3_errmsg(db));
    sqlite3_close(db);
   
    return NULL;
}

2) 쿼리 실행
nt sqlite3_prepare_v2(sqlite3 *db, const char *zSql, int nByte, sqlite3_stmt **ppStmt, const char **pzTail);
int sqlite3_step(sqlite3_stmt* stmt);
int sqlite3_finalize(sqlite3_stmt *pStmt);

쿼리는 prepare -> step -> finalize의 단계로 실행되고 종료됩니다. prepare는 쿼리실행에 앞서 쿼리를 컴파일하여 바이트코드로 변경합니다. step은 prepare에서 준비된 코드를 실행하며 실행될때 마다 다음 데이터를 가지고 옵니다. finalize는 prepare와 쌍으로 할당된 sqlite3_stmt의 메모리를 해제합니다.

사용 예)
if (sqlite3_prepare_v2(prevDB, "SELECT * FROM cross_temp", -1, &statement, NULL) == SQLITE_OK) {
    while (sqlite3_step(statement) == SQLITE_ROW) {
        int pid = sqlite3_column_int(statement, 0);
        NSLog(@"pid %d", pid);
    }
}
sqlite3_finalize(statement);

3) 결과값
int sqlite3_column_int(sqlite3_stmt*, int iCol);
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);

스텝에서 각 컬럼의 값들은 column_ 함수로 가져올 수 있습니다. 위는 int와 char*의 예이며 이외에도 각 타입에 맞는 함수들이 제공됩니다.

4) 쿼리 실행 - exec
int sqlite3_exec(sqlite3*, const char *sql, int (*callback)(void*,int,char**,char**), void *, char **errmsg);

exec은 위의 prepare, step, finalize를 동시에 실행하여 편리하게 사용할 수 있습니다. select와 같은 쿼리에서 각 단계의 데이터들은 콜백함수를 구현하여 처리할 수 있습니다.

사용 예)
if (sqlite3_exec(db, "SELECT * FROM item_info limit 10", setData, NULL, &error)) {
    NSLog(@"EXEC ERROR: %s", error);
    sqlite3_free(error);
}

콜백함수의 첫번째 인자는 sqlite3_exec의 4번째 인자에서 넘긴 사용자 데이터가 넘어 옵니다. cols는 전체 컬럼의 갯수이며 value, name에 각각 값과 컬럼명이 넘어 옵니다.
int setData(void* data,int cols, char** value, char** name) {

    for (int i = 0; i < cols; i++) {
        NSLog(@"%s, %s", value[i], name[i]);
    }
    return 0;
}


* 아이폰에서 쓰기 가능한 DB
어플리케이션은 실행시에 번들 내부의 파일에는 쓰기 권한이 없습니다. 그렇기 때문에 번들 내부에 있는 sqlite3 파일은 insert, update, delete와 같은 DB를 변경하는 쿼리가 실행되지 않습니다.

이를 해결하기 위해서는 Documents 디렉토리로 DB파일을 복사하고 이곳의 파일로 열어야 쓰기가 가능합니다. 애플의 아이폰 개발자 센터에 있는 SQLiteBooks 샘플에서 AppDelegate.m의 createEditableCopyOfDatabaseIfNeeded 메소드를 확인하시면 구현에 대해서 잘 나와있습니다. 그리고 아이폰에서 sqlite3 구현에 대한 간단한 내용은 이전 아이폰 SQLite3 샘플이란 포스팅에서 확인하실 수 있습니다.
AND

iOS 2009. 1. 13. 19:49
아이폰 SDK의 UIKit에는 문자열의 출력을 위해 NSString에 추가된 메소드들을 제공합니다. 이를 이용해서 UIView의 drawRect에서 직접 문자열을 출력하는 간단한 방법을 알아 보겠습니다. UIKit에 추가된 NSString의 메소드들에 대한 자세한 설명은 iPhone DevCenterNSString UIKit Additions Reference 문서에서 확인하실 수 있습니다.

1. 폰트 설정

폰트는 UIFont를 사용하여 설정할 수 있습니다. iPhone과 터치에서 사용가능한 폰트는 아래의 소스를 이용하여 확인할 수 있습니다.
NSArray* familyArray = [UIFont familyNames];
for (NSString *familyName in familyArray) {
    NSLog(@"- %@", familyName);  
    NSArray *fontArray = [UIFont fontNamesForFamilyName:familyName];
       
    for (NSString *fontName in fontArray) {
        NSLog(@"%@", fontName);
    }  
}

위 소스를 실행하면 아래와 같이 폰트들의 목록이 출력됩니다. 전체목록은 아래의 '모든 폰트 보기'를 클릭하시면 확인하실 수 있습니다.
- Georgia
Georgia-Bold
Georgia
Georgia-BoldItalic
Georgia-Italic


폰트명을 보면 볼드는 -bold와 이텔릭은 -Italic과 같이 되어 있어 각각의 특징을 알 수 있습니다. 폰트는 일반적으로 UIFont의 아래와 같은 메소드를 사용하여 생성합니다.
+ (UIFont *)fontWithName:(NSString *)fontName size:(CGFloat)fontSize

fontName에는 폰트명을 fontSize에는 크기를 설정하여 UIFont 오브젝트를 생성합니다. 아래는 위의 메소드를 이용하여 19 사이즈의 'Verdana-Bold' 폰트를 생성하는 예입니다.
UIFont *generalFont = [UIFont fontWithName:@"Verdana-Bold" size:19];

한글은 다른 폰트로 설정을 해도 영향을 받지 않는 것 같고 'AppleGothic'만 사용할 수 있는 것 같습니다.
 

2. 컬러 설정

컬러는 UIColor의 'colorWith...' 류의 생성 메소드로 직접 생성할 수 있지만 아래와 같이 미리 지장된 색상을 간편하게 이용할 수도 있습니다.
UIColor *generalColor = [UIColor darkGrayColor];

UIColor에서 지정되어 있는 색상은 아래와 같습니다.
black, darkGray, lightGray, white, gray, red, green, blue, cyan, yellow, magenta, orange,
purple, brown

색상설정은 set을 이용하여 간편하게 적용할 수 있습니다.
[generalColor set]


3. drawAtPoint

지정된 위치에 문자열을 출력하는 간단한 메소드입니다. 반환값은 실제 문자를 출력한 크기입니다.
- (CGSize)drawAtPoint:(CGPoint)point withFont:(UIFont *)font

point에 출력될 위치를 font에 사용될 폰트를 지정합니다.  다소 복잡하지만 아래의 메소드도 많이 사용됩니다.
- (CGSize)drawAtPoint:(CGPoint)point
forWidth:(CGFloat)width
withFont:(UIFont *)font
lineBreakMode:(UILineBreakMode)lineBreakMode

forWith는 문자열이 출력될 너비를 구합니다. fotWidth를 넘어 가는 문자들은 출력되지 않으며, lineBreakMode에 설정된 값에 따라 잘리는 옵션을 선택할 수 있습니다. 옵션은 아래와 같습니다. lineBreakMode의 옵션은 아래와 같습니다.

  • UILineBreakModeWordWrap - 단어 단위
  • UILineBreakModeCharacterWrap - 문자 단위
  • UILineBreakModeClip - 영역
  • UILineBreakModeHeadTruncation - 앞에 '...' 표시
  • UILineBreakModeTailTruncation - 뒤에 '...' 표시
  • UILineBreakModeMiddleTruncation - 중간에 '...' 표시

각 옵션의 결과는 아래의 샘플에서 확인하실 수 있습니다.


4. drawInRect

지정된 영역에 문자를 출력하는 메소드 입니다. 가로정렬이 가능하고 긴 문자열의 경우에는 여러줄에 걸쳐 출력을 할 수 있습니다.
- (CGSize)drawInRect:(CGRect)rect
withFont:(UIFont *)font
lineBreakMode:(UILineBreakMode)lineBreakMode
alignment:(UITextAlignment)alignment

drawAtPoint와 동일하며 alignment의 옵션은 아래와 같습니다.
  • UITextAlignmentLeft - 좌측 정렬
  • UITextAlignmentCenter - 중앙 정렬
  • UITextAlignmentRight - 우측정렬

5. 출력전 크기 구하기

출력전에 미리 출력될 문자열의 크기를 알아 낼 수 있는 'sizeWith...'류의 메소드들을 제공합니다. 출력시 사용하는 font와 width, lineBreakMode과 동일하게 설정하고 호출하면 출력될 텍스트의 실제 크기를 반환합니다.
- (CGSize)sizeWithFont:(UIFont *)font
forWidth:(CGFloat)width
lineBreakMode:(UILineBreakMode)lineBreakMode


drawInRect로 긴 문자열을 여러줄에 출력할 시에는 아래의 메소드를 호출해여 크기를 구해 와야 합니다.
- (CGSize)sizeWithFont:(UIFont *)font
constrainedToSize:(CGSize)size
lineBreakMode:(UILineBreakMode)lineBreakMode


6. 샘플

위의 메소드들을 이용해서 아래와 같이 간단한 예제를 만들어 보겠습니다. drawAtPoint의 breakMode별로 출력하고, 마지막에는 drawInRect를 이용하여 여러행에 걸쳐 출력하도록 하였습니다.
UIView 서브클래스의 drawRect에 아래와 같이 소스를 입력합니다.
- (void)drawRect:(CGRect)rect {
// 시작 x 좌표
#define START_X        10
   
    /* 텍스트 설정 (from wikipedia) */
    NSString *title = @"Tiger";
    NSString *memo = @"The tiger (Panthera tigris) is a member of the Felidae family;" \
                      "the largest of the four big cats";
   
    /* 폰트 설정 */
    UIFont *titleFont = [UIFont fontWithName:@"Arial-BoldItalicMT" size:40];
    UIFont *memoFont = [UIFont fontWithName:@"ArialMT" size:16];
   
    /* 칼라 설정 */
    UIColor *blackColor = [UIColor blackColor];
    UIColor *blueColor = [UIColor blueColor];
    UIColor *redColor = [UIColor redColor];
    UIColor *userColor = [UIColor colorWithRed:0.2 green:0.4 blue:0.2 alpha:0.8];
   
    CGFloat yPosition = 10;
    CGFloat viewWidth = [self bounds].size.width;
    CGSize textSize;
   
    /* 타이틀 출력 */
    [blueColor set];
    textSize = [title drawInRect:CGRectMake(0, yPosition, viewWidth, 30)
                        withFont:titleFont
                   lineBreakMode:UILineBreakModeWordWrap
                       alignment:UITextAlignmentCenter];
    yPosition = (textSize.height + 20);
       
    int mode = 0;   
    NSArray* breakModeArray = [NSArray arrayWithObjects:@"WordWrap",
                               @"CharacterWrap",
                               @"Clip",
                               @"HeadTruncation",
                               @"TailTruncation",
                               @"MiddleTruncation",
                               nil];

    /* breakMode 설정별로 텍스트 출력 */
    [blackColor set];
   
    for (NSString *modeName in breakModeArray) {
        /* 현재 breakMode 출력 */
        [redColor set];
        textSize = [modeName drawAtPoint:CGPointMake(START_X, yPosition)
                                forWidth:viewWidth
                                withFont:memoFont
                           lineBreakMode:UILineBreakModeWordWrap];
        yPosition += textSize.height;
       
        /* 텍스트 출력 */
        [blackColor set];
        textSize = [memo drawAtPoint:CGPointMake(START_X, yPosition)
                            forWidth:viewWidth-80
                            withFont:memoFont
                       lineBreakMode:mode];
        yPosition += (textSize.height + 8);
       
        mode++;
    }
   
    /* drawInRect 타이틀 출력 */
    [redColor set];
    textSize = [@"* drawInRect" drawAtPoint:CGPointMake(START_X, yPosition)
                                   forWidth:viewWidth
                                   withFont:memoFont
                              lineBreakMode:UILineBreakModeWordWrap];
    yPosition += textSize.height;
   
    /* memo를 drawInRect로 출력 */
    [userColor set];
    textSize = [memo drawInRect:CGRectMake(START_X, yPosition, viewWidth-80, 100)
                       withFont:memoFont
                  lineBreakMode:UILineBreakModeWordWrap];
}

AND

맨티스 1.1.1 버젼을 사용하다가 이번에 1.1.6 버젼으로 업그레이드를 했습니다. ChangeLog를 살펴보니 1년동안 업그레이드를 착실히 해온 것 같습니다. 새로운 버젼을 설치 하면서 과정과 사용법을 간단히 정리해 보았습니다.

맨티스 설치사양은 아래와 같습니다.

  • MySQL 4.1.1 이상
  • PHP 4.3.0 이상
  • 아파치, IIS등의 웹서버

1. 다운로드 및 설치
1) 다운로드
맨티스 다운로드 페이지나 혹은 프롬프트 상태에서 아래와 같이 맨티스 설치 파일을 다운로드 받은 후에 압축을 풉니다.
 
> wget http://downloads.sourceforge.net/mantisbt/mantisbt-1.1.6.tar.gz?modtime=1228833846&big_mirror=0
> tar xvzf mantisbt-1.1.6.tar.gz

2) 링크
mantis로 접근하기 위해 압축이 풀린 디렉토리에 심볼릭링크를 걸어줍니다.

> ln -s ./mantisbt-1.1.6 mantis

3) 설치
웹브라우져에서 http://[YOUR-DOMAIN]/mantis/admin/install.php를 실행하여 설치를 시작합니다. 먼저 아래와 같은 첫화면에서 DB 접속정보를 입력합니다.


MySQL 관리자 권한이 있는 계정을 'Admin Username'과 'Admin Password' 필드에 입력하시면 설정한대로 Database와 계정을 생성합니다. 입력을 완료한 후에 'Install/Upgrade Database' 버튼을 클릭합니다.

다음단계에서는 'Write Configuration File(s)'에 오류가 발생합니다. 이는 mantis 루트에 config_inc.php 파일을 생성할 권한이 없어서 입니다. 아래의 작업으로 해결할 수 있습니다.

4) config_inc.php 설정
기존 샘플 파일(config_inc.php.sample)을 아래와 같이 복사합니다.

> mv config_inc.php.sample ./config_inc.php

config_inc.php 파일을 열어 오류메시지에 있는 내용대로 아래와 같이 DB를 설정합니다.
$g_hostname = 'localhost';
$g_db_type = 'mysql';
$g_database_name = 'bugtracker';
$g_db_username = '[USER-NAME]';
$g_db_password = '[USER-PASSWORD]';

기본 메일계정을 설정합니다.
# --- email variables -------------
$g_administrator_email  = 'admin@YOUR-DOMAIN';
$g_webmaster_email      = 'admin@YOUR-DOMAIN';

# the "From: " field in emails
$g_from_email           = 'noreply@YOUR-DOMAIN';

# the return address for bounced mail
$g_return_path_email    = 'admin@YOUR-DOMAIN';

기본으로 한글사용을 위해 아래와 같이 추가합니다.
$g_default_language = "korean";

* admin 디렉토리 삭제
마지막으로 ./admin 디렉토리를 삭제합니다. admin 디렉토리는 초기설치와 관련된 파일들이 위치해 있어 설치후에는 필요가 없이 권한없이 접근할 수 있기 때문에 삭제합니다. 삭제하지 않으면 로그인 화면에서 오류가 표시됩니다.

> rm -dfr ./admin/

5) 로그인
웹브라우져에서 http://YOUR-DOMAIN/mantis 로 들어 갑니다. 아래와 같이 맨티스 사이트가 나오면 오류없이 설치된 것 입니다.

관리자 아이디인 'administrator'와 초기 기본 패스워드인 'root'를 입력하고 로그인 합니다. 관리자 패스워드는 계정관리로 들어가 반드시 변경해야 합니다.

2. 사용자 계정
'관리/사용자 관리' 메뉴로 들어가 '계정생성' 버튼을 클릭하여 사용자를 추가합니다. 계정 생성후에 상세한 옵션이나 권한을 설정할 수 있습니다.


이메일로 계정등록이 발송되기 때문에 이메일 주소를 정확히 입력하셔야 합니다. 테스트를 하여보니 제 서버에서는 이메일이 발송 되지 않았습니다. 

* 이메일 발송 오류
맨티스 루트디렉토리에 있는 config_defaults_inc.php에서 아래의 g_phpMailer_method를 0으로설정되어 있던 것을 아래와 같이 1로 변경하였더니 이메일이 정상적으로 발송되었습니다.

# select the method to mail by:
# 0 - mail()
# 1 - sendmail
# 2 - SMTP
$g_phpMailer_method     = 1;
 
같은서버에 있던 이전 버젼은 0으로 mail()을 사용해도 발송되었는데 이번 버젼에 문제가 있는 것인지 다른 문제가 있는 것인지 모르겠습니다. 저는 0일 경우에는 발송이 안되고 1과 2일 경우에는 발송이 되었습니다.

3. 프로젝트
1) 프로젝트 생성
'관리/프로젝트 관리' 메뉴로 들어가 새로운 프로젝트를 생성합니다. 역시 등록 후에 아래와 같은 상세한 설정을 할 수 있습니다.


2) 서브 프로젝트
연관된 서브프로젝트를 생성하고 관리할 수 있습니다.

3) 버젼
버젼을 등록하고 관리합니다.

3) 분류
이슈등록시 지정할 분류를 관리합니다.

4) 사용자
프로젝트에 관련된 사용자를 추가하고 권한을 설정할 수 있습니다.


4. 이슈 등록 및 확인
1) 사용자 등록
사용자 계정(testID)로 로그인하여 '이슈보고하기' 메뉴를 클릭합니다. 해당 프로젝트를 선택하고 버튼을 클릭하여 필드를 입력하고 등록합니다.


아래는 등록된 이슈목록입니다.

2) 관리자 확인
다시 관리자로 로그인 하면 메인화면에서 새로운 이벤트를 확인할 수 있습니다. 할당되지 않은 이슈에는 담당자를 할당하거나 바로 처리할 수 있습니다.


5. 기타
1) 위키
위키설정은 사실 큰 의미는 없습니다. config_default_inc.php파일에서 g_wiki_enable 속성을 ON으로 하면 메뉴에서 wiki의 링크가 추가됩니다.

#####################
# Wiki Integration
#####################
 
 # Wiki Integration Enabled?
 $g_wiki_enable = ON;

 # Wiki Engine (supported engines: 'dokuwiki', 'mediawiki', 'xwiki')
 $g_wiki_engine = 'dokuwiki';

 # Wiki namespace to be used as root for all pages relating to this mantis installation.
 $g_wiki_root_namespace = 'mantis';

 # URL under which the wiki engine is hosted.  Must be on the same server.
 $g_wiki_engine_url = $t_protocol . '://' . $t_host . '/%wiki_engine%/';

2) 사용자화
웹에서 관리 메뉴와 config_default_inc.php 파일을 변경하여 용도에 맞게 변경할 수 있습니다.

* 커스텀 필드 등록
아래와 같이 사용자 필드를 등록할 수 있습니다. 이외에 권한등 다양한 옵션이 있습니다.

등록된 필드를 프로젝트에 링크하며 해당 프로젝트의 이슈 등록시 사용자 등록필드가 출력됩니다.

* 디자인 변경
core 디렉토리의 html_api.php의 함수들을 수정하여 페이지마다 공통적인 top, bottom과 그외 다른 디자인을 변경할 수 있습니다.

이외에도 공지사항, 문서관리등과 함께 편리하게 이용할 수 있는 기능들이 많이 있습니다. 장단점이 있지만 개인적으로는 Trac보다는 Mantis가 편한 것 같습니다.

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

실버라이트2 동영상 재생 속도  (0) 2009.02.13
sqlite3 둘러보기  (3) 2009.02.02
애플스크립트(AppleScript) 둘러보기  (5) 2009.01.06
안드로이드 SDK - 바이오리듬 예제  (5) 2008.12.03
4. 기본 레이아웃 설정  (1) 2008.11.02
AND

그동안 OS X와 Xcode를 사용하면서 애플스크립트(AppleScript)란 단어를 간혹 들어 보고 샘플 코드를 본적은 있지만 실제 사용해 본적은 없었습니다. 코코아와 Objective-C를 둘러 보기도 벅찬데 애플스크립트까지 볼 여유가 안나서 차일피일 미루고 있었던 것 같습니다.

하지만 아무래도 맥을 잘 사용하고 어플리케이션을 효율적으로 만들기 위해서는 애플스크립트를 알고 있어야 할 것 같아 간단히 살펴 보았습니다. 아래는 애플스크립트 Example 폴더에 있는 'Finder Windows - Hide All'이란 샘플코드입니다.
보시다시피 프로그래밍 언어라기 보다는 일반 영어문장에 더 가까운 것 같습니다. 애플스크립트를 지원하는 여러 어플리케이션들의 기능과 조합하여 사용하면 다양한 작업을 할 수 있습니다. 이전까지는 그냥 쉘스크립트에서 확장된 언어인줄만 알았는데, 쉽고 재미있는 문법과 함께 편리하게 맥을 사용하고 개발을 할 수 있는 막강한 기능을 가지고 있는 것 같습니다.

 
1. 스크립트 편집기
애플스크립트를 작성하기 위해서는 스크립트 편집기를 사용합니다. 위치는 응용프로그램 / AppleScript 폴더 내에 있습니다. 이 폴더내의 Example Scripts를 보시면 각종 예제들을 확인하실 수 있습니다. 스크립트 편집기를 실행하면 아래와 같이 스크립트 편집기가 오픈됩니다.


1) 사전
애플스크립트의 장점은 애플과 다른 서드파티의 OS X 어플리케이션에서 제공하는 애플스크립트 지원기능을 사용하여 편리하게 어플리케이션을 조작할 수 있다는 것입니다. 지원하는 어플리케이션과 기능은 스크립트 에디터의 사전 목록에서 확인하실 수 있습니다. 스크립트 에디터의 메뉴에서 '파일/사전열기'를 클릭하거나 단축키(Command + Shift + O)을 입력합니다.
해당 어플리케이션을 더블클릭하면 속성과 기능들을 아래와 같이 확인하실 수 있습니다. 클릭하면 포함된 속성과 명령어들이 나오며 하단에서 항목에 대한 간단한 설명을 보실 수 있습니다. 

2) 코드 자동입력
스크립트 에디터에서 마우스 우클릭을 하면 아래와 같이 항목별로 자주 사용되는 코드들이 나열되어 있습니다. 필요한 항목을 선택하면 자동으로 에디터에 입력됩니다.

아래는 Tell Blocks의 Tell "Finder"를 클릭후에 자동으로 생성된 코드입니다.
tell application "Finder"
    -- insert actions here
end tell

3) 기록
스크립트 에디터의 툴바를 보면 '기록'이란 버튼이 있습니다. 기록은 지원하는 어플리케이션일 경우 사용자의 동작을 자동으로 스크립트로 변환해 주는 기능입니다. 사용방법은 '기록' 버튼을 클릭하고 해당 어플리케이션에서 스크립트로 생성될 행동을 하고 완료 후에는 '중단' 버튼을 클릭합니다.

아래는 파인더에서 어플리케이션 폴더를 열고 스크립트 에디터를 실행하는 과정이 스크립트로 자동으로 기록된 내용입니다. 
tell application "Finder"
    activate
    set target of Finder window 1 to folder "Applications" of startup disk
    set target of Finder window 1 to folder "AppleScript" of folder "Applications" of startup disk
    open application file "Script Editor.app" of folder "AppleScript" of folder "Applications" of startup disk
end tell

자동으로 소스코드를 생성해주는 것도 편하지만 문법을 잘 모를 경우에 이 '기록' 기능을 이용하여 확인하면 편리할 것 같습니다.


2. 예제
1) Hello World!
간단히 다이알로그박스를 열고 Hello World를 읽어주는 스크립트를 작성해 보겠습니다. 아래의 내용을 스크립트 에디터 상단의 편집창에 입력하고 컴파일 버튼을 클릭합니다.

display dialog "Hellow World!" buttons {"닫기", "말하기"} default button "말하기"
if the button returned of the result is "말하기" then
    say "Hellow World"
end if

컴파일전에는 보라색으로 소스가 출력되지만 오류가 없이 컴파일이 완료되면 아래와 같이 문법이 컬러링 되어 출력됩니다.

이제 스크립트 에디터의 실행버튼을 클릭하면 아래와 같이 다이알로그박스가 열리며, 우측의 말하기 버튼을 클릭하면 Hello World 음성이 출력됩니다.

2) 새 메시지
메일에서 새로운 메시지를 작성하는 간단한 애플스크립트를 작성해 보겠습니다. outgoing messqage의 subject, content, visible 프로퍼티를 설정하여 메일의 새로운 메시지 창을 오픈하는 스크립트 입니다.
(*
아래의 내용으로 새로운 메일을 생성합니다.

제목: 안녕하세요?
내용: 반갑습니다.
수신: zzerrrrr@gmail.com
*)
tell application "Mail"
    -- 새로운 메일 생성
    set newMessage to make new outgoing message with properties {subject:"안녕하세요?", content:"반갑습니다", visible:true}
   
    -- 수신자를 설정한다   
    tell newMessage
        make new to recipient with properties {name:"zzerr", address:"zzerrrrr@gmail.com"}
    end tell
   
    activate
end tell

* 주석
주석은 (*로 시작하여 *)로 종료됩니다. 다른 언어의 '/* */' 방식과 동일합니다. 한줄 주석은 '--'를 앞에 붙여 사용합니다.

* tell 
tell은 메시지를 수신할 해당 객체를 지정합니다. 각 구문은 'tell'로 시작하여 'end tell'로 종료합니다. tell application "Mail"은 메일 어플리케이션에 메시지를 발송한다는 의미입니다.

* set ~ to ~ 
객체에 값을 설정합니다. set A to B는 말 그대로 A를 B로 설정한다는 의미입니다.
 
* with properties {name:value, ...}
생성된 오브젝트 속성들의 값을 지정합니다.

실행버튼을 클릭하면 아래와 같이 스크립트에서 지정한 속성으로 새로운 메시지를 보내는 창이 오픈됩니다. 

3. 기타
1) 실행파일로 저장
스크립트 편집기의 메뉴에서 파일/별도저장을 클릭하면 아래와 같이 몇가지 파일포맷을 지정하여 저장할 수 있습니다.


파일포맷중 응용 프로그램이나 응용 프로그램 번들로 저장하면 스크립트 에디터 없이 바로 실행할 수 있는 실행파일로 저장할 수 있습니다.

2) 참고 자 및 사이트
저도 잠시 사용해보고 글을 올리는 것이라 부정확하고 틀린 내용이 많이 있을 것 같습니다. 자세하고 정확한 내용은 아래의 관련 문서와 사이트들을 참조하시기 바랍니다.

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

sqlite3 둘러보기  (3) 2009.02.02
버그추적 시스템 Mantis 설치  (6) 2009.01.07
안드로이드 SDK - 바이오리듬 예제  (5) 2008.12.03
4. 기본 레이아웃 설정  (1) 2008.11.02
구글 안드로이드 소스 공개와 마켓 오픈  (2) 2008.10.23
AND

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. 시작하기

'iOS' 카테고리의 다른 글

UITableView의 메모리 누수 현상  (4) 2009.02.05
UIView에서 텍스트 출력  (10) 2009.01.13
아이폰 SQLite3 샘플  (5) 2008.11.25
재미있는 아이팟 터치용 게임들  (9) 2008.11.23
iPhone SDK 2.2 업데이트  (4) 2008.11.22
AND

실버라이트는 그동안은 런타임조차 설치를 안했을 정도로 관심이 없었고, 그저 플랙스 비슷한 것이 있나 보다 하고 생각하고 있었습니다.

그러다가 갑자기 호기심이 생겨 이제서야 실버라이트 개발환경을 만들어 보고 잠깐 살펴보았습니다. 실버라이트2는 MS에서 나온 RIA(Rich Internet Application)로, 자세한 설명은 MSDN의 실버라이트 한글문서에 잘 나와 있습니다.

* 참조 사이트
아래의 사이트들에서 개발에 필요한 메뉴얼과 샘플을 얻을 수 있습니다.

  • Silverlight Lean - 실버라이트 공식홈페이지로 다양한 문서들과 동영상 강좌, 튜토리얼등이 있습니다.  
  • MSDN Silverlight - MSDN의 실버라이트 색션입니다. 원하는 항목을 쉽게 찾을 수 있고, 항목별로 간단한 샘플등을 확인할 수 있씁니다.

관련 사이트외에도 CHM버젼의 SDK 도움말도 다운로드 받아 사용하실 수 있습니다.


1. 개발환경 설치
설치는 실버라이트의 공식 홈페이지에서 Get Started 문서를 참조하였습니다. 해당 페이지에는 아래와 같이 관련링크와 함께 간단한 설명이 되어 있어 쉽게 설치를 할 수 있습니다. 



1) Silverlight Tools for Visual Studio 2008 SP1
실버라이트 툴즈를 설치하기 위해서는 먼저 Visual Studio 2008 SP1과 Visual Web Developer Express with SP1가 설치되어 있어야 합니다. 이 패키지는 SDK와 개발 런타임, Visual Studio에 관련 기능과 C#/Visual Basic에서 사용할 수 있는 템플릿들을 설치합니다.

저는 일단 권장하는데로 모두 설치를 하였지만 막상 사용을 해보니, 이 패키지 하나만 설치를 하면 기본적인 실버라이트의 개발은 가능할 것 같습니다.

2) Microsft Expression Blend 2 + SP1
60일 트라이얼 버젼을 설치하여 잠시 실행해 보았습니다. UI를 디자인하고 타임라인등의 용어가 있는 것으로 보아 애니메이션을 제작하는 툴 같습니다. 아마 어도비의 플래쉬와 비슷한 개념의 툴인 것 같습니다.


3) Deep Zoom Composer
이미지 관련툴인 것 같은데 사용해보지는 않았습니다.

4) Silverlight Toolkit
실버라이트 어플리케이션에서 사용할 수 있는 콘트롤, 컴퍼넌트, 유틸리티등이 있다고 하는데 역시 사용해 보지는 않았습니다.

2. 테스트 드라이브
1) 동영상 플레이어
동영상을 플레이, 일시중지, 중지를 할 수 있는 간단한 어플리케이션을 만들어 보았습니다. 이런 개발툴에서는 기본기능의 동영상 플레이어는 간단하게 만들어 볼 수 있기 때문입니다.


2) 프로젝트 생성
VS의 New Project에서 프로젝트 템플릿을 아래와 같이 C# / Silverlight / Siverlight Application으로 선택합니다.
 

그런데 프로젝트를 생성하지 못하고 오류가 발생하였습니다. 검색을하여 보니 관련 내용이 있어  아래와 같이 명령 프롬프트에서 실행하고 해결하였습니다.

C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\devenv.com /resetskippkgs  

3) 소스코드 수정
레이아웃을 지정하는 xaml과 동작을 실행하는 C# 소스파일에 아래와 같이 내용을 추가합니다.

* Page.xaml
<UserControl x:Class="SilverlightMovieTest.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="400" Height="330">
    <Canvas x:Name="LayoutRoot" Background="White">
<MediaElement AutoPlay="False" x:Name="mediaPlayer"
Source="[동영상 URL]"
Width="400" Height="300"></MediaElement>

<Button x:Name="btnPlay" Canvas.Top="310" Content="Play"
Width="60" Height="20"/>

<Button x:Name="btnStop" Canvas.Top="310" Canvas.Left="64"
Content="Stop" Width="60" Height="20"/>

</Canvas
</UserControl>
[동영상 URL] 부분에 해당 동영상의 URL을 입력합니다.

* Page.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SilverlightMovieTest
{
    public partial class Page : UserControl
    {
        bool isPlay = false;

        public Page()
        {
            InitializeComponent();

            /* 버튼 이벤트 핸들러 설정 */
            btnPlay.Click += new RoutedEventHandler(PlayButtonClicked);
            btnStop.Click += new RoutedEventHandler(StopButtonClicked);
           
            btnStop.IsEnabled = false;
        }

        /** Play 버튼 클릭 시 */
        void PlayButtonClicked(object sender, RoutedEventArgs e)
        {
            if (isPlay == false)
            {
                mediaPlayer.Play();

                btnPlay.Content = "Pause";
                btnStop.IsEnabled = true;
                isPlay = true;
            }
            else
            {
                mediaPlayer.Pause();

                btnPlay.Content = "Play";
                btnStop.IsEnabled = false;
                isPlay = false;
            }
        }

        /** Stop 버튼 클릭 시 */
        void StopButtonClicked(object sender, RoutedEventArgs e)
        {
            if (mediaPlayer.CurrentState == MediaElementState.Playing)
            {
                mediaPlayer.Stop();
                               
                btnPlay.Content = "Play";
                btnStop.IsEnabled = false;
                isPlay = false;
            }
        }
    }
}


실행을 해보면 아래와 같이 인터넷 익스플로어에서 구동되는 모습을 확인할 수 있습니다.



3. 배포
빌드를 하면 프로젝트명.xap 파일이 생성됩니다. 확장자명을 보면 IIS에서만 실행될 것 같은 느낌이 들지만, 플래쉬의 swf와 같이 로컬의 런타임에서 실행되기 때문에 웹서버와는 상관이 없습니다.

웹사이트에서 실버라이트를 실행하기 위해서는 아래와 같이 HTML을 작성합니다. 자세한 내용은 MSN의 Add Silverlight to Web Page by Using HTML 문서에 잘 나와있습니다. 

<object width="400" height="300" data="data:application/x-silverlight-2," type="application/x-silverlight-2">
    <param name="source" value="./SilverlightMovieTest.xap"/>
 
    <!-- Display installation image. -->
    <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>  

<!-- Display installation image. --> 아래 있는 HTML은 실버라이트 런타임이 설치되지 않았을 경우에는 우측과 같은 이미지와 링크를 제공합니다.


사실 간단히 맛만 봐서 '실버라이트2 맛보기'란 제목으로 넣고 싶었는데, 맛보기란 제목이 들어가면 제 의도와는 다른 검색어로 들어 오는 분들이 많으셔서 그냥 둘러 보기로 했습니다.

그동안 몇몇 다른 개발툴들에 대해서 '맛보기' 형식으로 쓴 적이 있는데, MS의 개발툴에 관련된 내용은 처음으로 올리는 것 같습니다. 아무래도 블로그 제목대로 맥을 기반으로한 프로그래밍에 관해 다루어야 한다는 생각이 있었던 것 같은데, 이제부터 관심있는 부분은 가리지 않고 올려 볼려고 합니다.

'개발 툴' 카테고리의 다른 글

PhoneGap 설치  (4) 2012.02.14
OS X에서 Go 설치  (0) 2010.02.27
프로젝트 관리 도구 OpenProj  (2) 2008.03.21
적당히 참견하는 Xcode  (4) 2008.02.25
OS X의 파이썬  (0) 2008.02.20
AND

Xcode를 사용하면서 도움말을 잘 이용하시면 많은 궁금증과 의문점을 쉽게 해소할 수 있습니다. 모르는 것에 대해서 도움말 보다는 구글에서의 검색과 관련 커뮤니티에 질문을 올리는 것은 쉽고 편한 방법일 수는 있어도 장기적으로는 바람직하지  않습니다. 먼저 도움말을 찾아 보고 그래도 답을 찾을 수 없을 때에 비로소 후자의 방법을 택해야 합니다.

다소 늦고 귀찮은 것 같더라도 도움말을 이용하면 원칙에 가까운 답을 얻어 낼 수 있고, 검색하거나 다른 중요한 사항들도 알아낼 수 있습니다. 도움말은 영문으로 되어 있지만 대부분 코드와 간단한 문장이기 때문에 저같이 영어를 잘 몰라도 대부분 쉽게 이해할 수 있습니다.
 
Xcode를 처음 사용하시거나 프로그래밍을 처음 하시는 분들을 위해서 간단하게 도움말을 이용하는 방법을 알아 보겠습니다.

1. Documentation
Xcode의 Help메뉴에서 Document를 클릭하거나 단축키(Shift+Command+Option+?)를 입력하면 아래와 같이 도큐먼트 창이 오픈됩니다.


1) 도움말 다운로드
Xcode의 도움말은 해당항목들을 다운로드 받으신 후에 사용할 수 있습니다. 원하시는 도움말 항목에서 SUBSCRIBE나 GET 버튼을 클릭하여 로컬로 다운로드 받아야 해당 도움말이 활성화 되고 사용할 수 있습니다.

2) 검색어


검색을 위해서는 우측 상단의 Starts With에 검색할 키워드를 입력합니다. 검색어는 &(AND), !(NOT), |(OR) 연산을 지원합니다.

(string | value)  & !format
위와 같은 입력은 string 또는 value를 포함하고 format을 포함하지 않는 항목을 검색합니다.

4) 검색 대상


  • API - 심볼명(클래스, 메소드등)에서 검색합니다.
  • Title - 문서의 제목에서 검색합니다.
  • Full-Text - 문서의 전체 내용에서 검색합니다.

5) 문서 범위


All Doc Sets는 전체문서에서 검색을 하며 우측에는 DOC SETS에서 현재 검색 범위를 표시합니다.

6) 언어 선택


All Languages는 전체 언어(Objective-C, C/C++, Java, Javascript)에서 검색을 합니다. 우측에는 현재 선택된 언어들이 표시되어 있습니다.

전체언어 다음에 선택될 언어들은 위의 API Options 버튼을 클릭하여 선택할 수 있습니다.


7) 검색 조건


검색창에 입력한 문장이 검색될 조건을 지정합니다.

  • Starts With - 입력된 검색어로 부터 시작되는 항목을 출력합니다.
  • Contains - 입력된 검색어가 포함된 항목을 출력합니다.
  • Exact - 입력된 검색어가 일치된 경우만 출력합니다.

2. Research Assistant
Xcode의 Help메뉴에서 Show Research Assistant를 클릭하거나 단축키(Shift+Control+Command+?)를 입력하면 아래와 같이 Research Assistant가 오픈됩니다.


Research Assistant가 오픈되어 있으면 Xcode의 에디터에서 커서가 위치한 곳에 해당항목에 대한 도움말이 있으면 자동으로 위와 같이 간단한 도움말과 관련 API, 문서, 샘플등을 표시해주는 아주 유용한 툴입니다. 듀얼 모니터를 사용하시는 분들은 Xcode 사용시 다른 모니터에 뛰워 놓으시면 편리하게 확인하실 수 있습니다.

3. 기타
1) 도움말 바로가기 (Option + 마우스 더블클릭)
Xcode의 에디터에서 옵션키를 누른 상태에서 레퍼런스 내용을 확인할 단어에다 마우스로 더블클릭을 하면 해당내용이 도큐멘테이션에서 바로 출력이 됩니다.

2) 선언 보기 (Command + 마우스 더블클릭)
Xcode의 에디터에서 커멘드키를 누른 상태에서 변수나 메소드등의 심볼을 클릭하면 해당 변수/메소드가 선언(또는 구현)된 소스파일로 이동합니다.

이외에 Xcode와 도움말에 대한 자세한 내용은 ADCXcode Workspace Guide 문서를 참조하시기 바랍니다.

AND

안드로이드 개발환경을 조금 더 살펴 볼려고 간단히 어플리케이션을 만들어 보았습니다. 처음 대쉬보드 바이오리듬을 시작한뒤로 바이오리듬을 너무 우려먹고 있는 것 같습니다. SDK의 설치나 사용방법은 이전에 포스팅한 구글 Android 개발환경 둘러 보기를 참조하시면 좋을 것 같습니다. 아래의 이미지는 에뮬레이터에서 실행한 모습입니다.


요즘 개발환경으로는 드물게 마우스 사용없이 GUI를 구현해야 하지만 레이아웃을 편집하면서 확인할 수 있으니 큰 불편은 없는 것 같습니다. 아래는 사용한 소스들과 간단한 설명입니다. 이클립스에서 안드로이드 프로젝트로 Biorhythm을 생성하고 각각의 소스를 아래와 같이 수정하시고, BioView.java를 추가하시면 위와 같이 실행해 보실 수 있습니다.

* Biorhythm.java
package com.zzerr;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class Biorhythm extends Activity {
    private BioView bioView;
    private EditText inputYear, inputMonth, inputDay;
   
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
        setContentView(R.layout.main);
       
        bioView = (BioView)findViewById(R.id.myView);
       
        inputYear = (EditText)findViewById(R.id.inputYear);
        inputMonth = (EditText)findViewById(R.id.inputMonth);
        inputDay = (EditText)findViewById(R.id.inputDay);
       
        /** 버튼이 클릭되었을 경우 바이오리듬 출력 */
        Button button = (Button)findViewById(R.id.showButton);
        button.setOnClickListener(new Button.OnClickListener() {
            public void onClick(View v) {
                bioView.setBirthDay(Integer.parseInt(inputYear.getText().toString()),
                        Integer.parseInt(inputMonth.getText().toString()),
                        Integer.parseInt(inputDay.getText().toString()));
               
                bioView.invalidate();
            }
        });
    }
}


* BioView.java
View 클래스에서 상속 받아 main.xml에서 정의한 myView를 서브클래싱하는 클래스입니다. 바이오리듬을 계산한 후에 출력을 합니다.
package com.zzerr;

import android.view.View;
import android.content.Context;
import android.util.AttributeSet;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.Log;

import java.util.Date;

public class BioView extends View {
    /** 상수 */
    private static final int mMaxDays = 30;
    private static final int mMaxType = 3;
    private static final long mTDV = (60*60*24*1000);
    private static final double mPI = 3.14159;
   
    private static final double mBioValues[] = { 23.0, 28.0, 33.0 };
    private static final int mColors[] = { 0xff0000ff, 0xffff00ff, 0xff00ffff };
   
    /** 멤버변수 */
    private Paint mPaint;
    private Rect mRect;
    private double mStartDays;
    private Date mBirthDate, mTodayDate;
       
    public BioView(Context context, AttributeSet attrs) {
        super(context, attrs);
       
        mRect = new Rect();
        mPaint = new Paint();
       
        mRect.top = 0;
        mRect.bottom = getWidth();
        mRect.left = 0;
        mRect.right = getHeight();

        mTodayDate = new Date();
        Date startDate = new Date(mTodayDate.getYear(), mTodayDate.getMonth(), 1);
       
        mStartDays = startDate.getTime()/mTDV;
        mBirthDate = new Date();
       
        mBirthDate.setYear(0);
    }
   
    public void setBirthDay(int year, int month, int day) {
        mBirthDate.setYear(year);
        mBirthDate.setMonth(month);
        mBirthDate.setDate(day);
    }

   @Override
   protected void onDraw(Canvas canvas) {
        int cellWidth = getWidth()/mMaxDays;
       
        mRect.top = 0;
        mRect.bottom = getWidth();
        mRect.left = 0;
        mRect.right = getHeight();
       
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(0xFFFFFFFF);

        int x = 0, y = 0, oldY = 0;
         
        // 세로줄 출력
        for (int i = 0; i <= mMaxDays; i++) {
            x += cellWidth;
            canvas.drawLine(x, mRect.top, x, mRect.bottom, mPaint);
        }
         
        // 가로줄 출력
        canvas.drawLine(0, mRect.bottom/2, mRect.right, mRect.bottom/2, mPaint);
      
        // 오늘 날짜 출력
        mPaint.setColor(0xFFFFFF00);
        x = cellWidth * mTodayDate.getDate();
        canvas.drawLine(x, mRect.top, x, mRect.bottom, mPaint);
              
        // 바이오리듬 출력
        if (mBirthDate.getYear() != 0) {
            Log.e("LOG", "year:" + mBirthDate.getYear() +
                    "month:" + mBirthDate.getMonth() +
                    "day:" + mBirthDate.getDate());
           
            double startDays = mStartDays;
            double birthDays = mBirthDate.getTime()/mTDV;
                 
            for (int k = 0; k < mMaxType; k++) {
                x = 0;
             
                mPaint.setColor(mColors[k]);
             
                for (int i = 0; i <= mMaxDays; i++) {
                    double gab = birthDays - startDays;
                    double p = (int)(Math.sin((gab/mBioValues[k]) * 2.0 * mPI) * 100.0);
   
                    y = mRect.bottom/2 + (int)(p * ((mRect.bottom/2.0)/100.0));
                   
                    if (i != 0)
                        canvas.drawLine(x, oldY, x + cellWidth, y, mPaint);
                   
                    oldY = y;
                    startDays++;
                    x += cellWidth;
                }
            }
        }
        
        super.onDraw(canvas);
    }
}

* main.xml
GUI를 정의하는 곳입니다. 이곳에서의 수정은 아래의 R.java의 R 클래스에 자동으로 적용이 됩니다. com.zzerr.BioView와 같이 사용자 클래스도 정의하여 사용할 수 있습니다.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#666666"
    >

<com.zzerr.BioView android:id="@+id/myView"
    android:layout_width="fill_parent"
    android:layout_height="330px"
    android:background="#000000"
    />
   
<TextView android:id="@+id/helpLabel"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_below="@id/myView"
    android:layout_marginTop="20px"
    android:text="생년월일을 입력후에 보기버튼을 클릭해 주세요."
    />

<EditText android:id="@+id/inputYear"
    android:layout_width="80px"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:text=""
    />

<EditText android:id="@+id/inputMonth"
    android:layout_width="60px"
    android:layout_height="wrap_content"
    android:layout_toRightOf="@id/inputYear"
    android:layout_alignTop="@id/inputYear"
    android:text=""
    />

<EditText android:id="@+id/inputDay"
    android:layout_width="60px"
    android:layout_height="wrap_content"
    android:layout_below="@id/myView"
    android:layout_toRightOf="@id/inputMonth"
    android:layout_alignTop="@id/inputMonth"
    android:text=""
    />
       
<Button android:id="@+id/showButton"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_alignParentRight="true"
     android:layout_marginLeft="10px"
     android:layout_toRightOf="@id/inputDay"
     android:layout_alignTop="@id/inputDay"
     android:text="보기"
     />

</RelativeLayout>

* R.java
주석에 설명되어 있는 것과 같이 자동으로 생성해 주는 파일입니다. main.xml을 편집하면 자동으로 그에 맞게 내용이 변경됩니다.
/* AUTO-GENERATED FILE.  DO NOT MODIFY.
 *
 * This class was automatically generated by the
 * aapt tool from the resource data it found.  It
 * should not be modified by hand.
 */

package com.zzerr;

public final class R {
    public static final class attr {
    }
    public static final class drawable {
        public static final int icon=0x7f020000;
    }
    public static final class id {
        public static final int helpLabel=0x7f050001;
        public static final int inputDay=0x7f050004;
        public static final int inputMonth=0x7f050003;
        public static final int inputYear=0x7f050002;
        public static final int myView=0x7f050000;
        public static final int showButton=0x7f050005;
    }
    public static final class layout {
        public static final int main=0x7f030000;
    }
    public static final class string {
        public static final int app_name=0x7f040001;
        public static final int hello=0x7f040000;
    }
}

Xcode와 Objective-C를 사용하는 아이폰 개발과는 달리 많은 개발자들에게 익숙한 이클립스와 Java를 사용하고, 윈도우 PC에서도 개발이 가능하니 시작하기는 더 쉬울 것 같다는 생각이 듭니다. 개발자 등록도 25달러로 더 저렴하고요. ^^
AND

미국의 App 스토어의 어플리케이션수가 거의 10,000개에 다다른다는 소식이 있습니다. 현재까지 나온 어플리케이션을 모두 구입하는데는 약 3만달러가 든다고 합니다. App 스토어가 오픈한지 5개월 정도 지난 것 같은데 하루에 60개 이상씩 런칭된 것 같습니다. 앞으로도 어플이케이션의 수는 계속 증가될 것으로 보입니다.


아마 많은 터치 사용자들이 종종 App 스토어에 들러 새로 나온 어플리케이션도 둘러 보며, 필요한 소프트웨어를 다운로드 받는 것을 즐기는 분들이 많으실 것으로 생각됩니다. 터치는 기기 자체도 좋지만 이런 풍부한 소프트웨어가 장점인 것 같습니다.


구글의 안드로이드 마켓에도 재미있어 보이는 어플리케이션들이 많이 보이네요. 아마 유료 소프트웨어를 판매하는 내년 초가 되면 안드로이드용 소프트웨어도 많이 나올 것으로 보입니다. 앞으로 애플의 아이폰과 구글의 안드로이폰의 경쟁을 지켜보는 것도 재미가 있을 것 같습니다. 이런 경쟁에 우리나라 업체가 하나 있었으면 하는 아쉬움도 드네요.

아이팟 터치가 있으니 핸드폰은 아이폰 보다 안드로이드폰을 구입 해야 겠다는 생각이 듭니다. 이 두개만 있으면 외출시에도 심심할 일은 없을 것 같습니다.

'App Store' 카테고리의 다른 글

사전 어플리케이션  (0) 2009.05.01
아이폰 App - Action Counter  (26) 2009.04.30
스모킹 카운터 1.2 버그  (0) 2009.03.18
Smoking Counter 등록 완료  (64) 2009.03.03
제 계정으로 처음 어플리케이션을 등록했습니다  (28) 2009.02.26
AND

iOS 2008. 11. 25. 14:18
SQLite는 경량화된 DB로 맥과 아이폰/아이팟 터치에 기본적으로 내장되어 편리하게 사용할 수 있습니다. 자세한 내용은 SQLite 공식 홈페이지와 아래의 문서들을 참조하시면 도움이 되실 것입니다.


이와함께 애플의 iPhoneDev Center SQLite Book List란 샘플을 보시면, 아이폰 SDK에서 사용하는 방법이 잘 나와있습니다. SQLite의 개발자인 Richard Hipp이 구글 테크토크에서 직접 SQLite에 대해서 설명하는 'An Introducion to SQLite'란 동영상도 참고하면 좋습니다.



아래는 제가 SQLite를 테스트 해보기 위해 만들어 본 간단한 샘플코드입니다. 아이폰에서 사용자로 부터 입력을 받은 후에 SQLite DB에 저장하는 간단한 샘플입니다. DB를 오픈하는 부분과 SELECT, INSERT하는 부분만 참고하시면 쉽게 사용하실 수 있습니다.

* SQLiteTestAppDelegate.h
#import <UIKit/UIKit.h>
#import <sqlite3.h>

@interface SQLiteTestAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
    sqlite3 *db;
    NSMutableArray *dataList;

    IBOutlet UITextField *newString;
    IBOutlet UITableView *dataTable;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

- (void)updateDataList;

- (IBAction)addRow:(id)sender;
   
@end


SQLiteTestAppDelegate.m
#import "SQLiteTestAppDelegate.h"

@implementation SQLiteTestAppDelegate

@synthesize window;

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

    // Override point for customization after application launch
    [window makeKeyAndVisible];
   
    /* 어플리케이션 패스를 구한다. */    
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *path = [documentsDirectory stringByAppendingPathComponent:@"mydata.db"];
       
    /* 데이터베이스를 오픈한다 */
    if(sqlite3_open([path UTF8String], &db) == SQLITE_OK) {
        char *error = NULL;
        const char* query = "SELECT count(*) from mytable";
       
        /* mytable을 쿼리해보고 오류가 있으면 mytable을 생성한다. */
        if (sqlite3_exec(db, query, NULL, 0, &error) != SQLITE_OK) {
            sqlite3_free(error);
           
            /* 테이블 생성 */
            if (sqlite3_exec(db, "CREATE TABLE mytable ('name' CHAR(16))", NULL, 0, &error) != SQLITE_OK) {
                NSLog(@"TABLE CREATE ERROR: %s", error);
                sqlite3_free(error);
            }   
        }
    } else {
        /* DB 오픈 에러 */
        sqlite3_close(db);
        db = NULL;
       
        NSLog(@"DB OPEN ERROR: '%s'", sqlite3_errmsg(db));   
    }
   
    dataList = [[NSMutableArray alloc] initWithCapacity:100];
   
    [self updateDataList];
}

- (void)applicationWillTerminate:(UIApplication *)application {
    if (db) {
        sqlite3_close(db);
    }
}

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

/** 현재 DB에 있는 데이터를 dataList에 등록 */
- (void)updateDataList {
   
    /* 이전 데이터를 모두 삭제 */
    [dataList removeAllObjects];
   
    const char *query = "SELECT name FROM mytable";
    sqlite3_stmt *statement;
   
    if (sqlite3_prepare_v2(db, query, -1, &statement, NULL) == SQLITE_OK) {
        while (sqlite3_step(statement) == SQLITE_ROW) {
           
            /* dataList에 쿼리결과 등록 */
            NSString* str = [[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(statement, 0)];
            [dataList addObject:str];
            [str release];
        }
    }
    sqlite3_finalize(statement);

    [dataTable reloadData];
}


#pragma mark IBACTION

- (IBAction)addRow:(id)sender {

    char *error = NULL;
   
    /* 사용자가 입력한 값을 DB에 추가한다 */
    NSString *query = [NSString stringWithFormat:@"INSERT INTO mytable VALUES ('%@')", [newString text]];
    sqlite3_exec(db, [query UTF8String], NULL, 0, &error);
   
    [self updateDataList];
}


#pragma mark TextField Delegate method

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
   
    [textField resignFirstResponder];
    return YES;
}


#pragma mark TableView Delegate method

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    return @"Table Items";
}

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
   
    static NSString *cellIdentifier = @"Cell";
   
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:cellIdentifier] autorelease];
    }
    cell.text = [dataList objectAtIndex:indexPath.row];
   
    return cell;
}

@end

AND

요즘은 어디 나갈 때 핸드폰보다 터치를 더 챙기게 되었습니다. NDS도 있지만 아기자기한 게임들을 기울기와 터치로 즐기는 색다른 재미에, 가족들 사이에서도 터치의 게임이 훨씬 더 인기가 좋습니다. 제가 요즘 터치에서 가장 즐겨하는 게임은 Smallware에서 나온 Sol Free라는 카드게임입니다. (유료지만 무료 버젼도 있습니다.) 화장실에도 들고 갑니다. ^^;;


이전에 윈도우에서도 심심풀이로 많이 했지만, 터치에서는 직접 손으로 카드를 옮기고 넘기는 손맛때문에 한층 재미가 더 한 것 같습니다. 컴퓨터의 마우스로는 이 맛이 느낄 수 없어 재미가 없습니다.

다음으로 Rocking Porket Games에서 나온 Blue Skies란 게임도 간혹 하고 있습니다. 유료게임이지만 무료로된 lite 버젼을 설치하였습니다. 대공과 대지 공격을 하는 헬리콥터를 조정하여 적들을 찾아 파괴하는 게임입니다. 기울여서 방향을 조종하기 때문에 조금 반응이 늦는 감은 있지만, 헬리콥터의 움직임과는 잘 어울리는 것 같습니다.

그리고 오늘 App 스토어에서 또 다른 재미있는 게임을 찾았습니다. 작년 초에 아이맥에서 가끔 하고 저의 다른 블로그에서도 소개했던 3D 슈팅게임인 sauerbraten이 아이폰, 터치용으로 포팅이 되어 sauerbraten의 이전 이름인 Cube란 게임으로 나왔습니다.


위는 터치에서 캡쳐한 게임화면입니다. 터치를 돌리면서 진행 방향을 정하고 아래와 같이 외각을 터치해서 움직이고 총을 쏘고 점프를 할 수 있습니다.


이전에 컴퓨터에서 했던 게임을 똑같이 터치에서 할 수 있다는게 신기하긴 하지만, 컨트롤이 터치에서 제가 하기엔 너무 어려운 것 같습니다. 익숙해지면 좀 나아질지 모르겠습니다. PC용 버젼은 전체소스가 공개되어 있는데 터치용 버젼의 소스는 공개가 되지 않은 것 같습니다.

한번씩 App 스토어를 들어가면 이런 재미있는 공짜 게임들이 많이 올라오니, 사용자 입장에선 참 행복하고 고마운 일입니다. 이제는 초기에 비해서 완성도가 꽤나 높은 게임들이 무료나 lite 버젼으로 많이 올라오고 있는 것 같습니다.

애플은 아이폰 개발자 유니버시티 프로그램을 추가하여 대학생들이 공부를 목적으로 무료로 아이폰 어플리케이션을 사용하고 기기에서 테스트 해 볼 수 있는 지원을 하고 있습니다. 이와 마찬가지로 공개 소프트웨어 개발자에게도 무료 개발자 프로그램 등록과 같은 혜택을 주었으면 좋겠습니다.
AND