iPhone/강좌2009/03/10 21:37
Window는 컨텐츠를 출력하는 역할을 수행하고,  Views는 컨텐츠를 구성하고 그리는 역할을 수행합니다. Window는 MS Windows와 비교하였을 때 메인 다이얼로그, Views는 컨트롤이라고 생각해도 무방합니다. 일반적으로 아이폰 어플리케이션은 1개의 Window와 여러개의  Views로 구성됩니다. 어플리케이션이 생성될 때 UIWindow 클래스의 인스턴스가  아이폰 어플리케이션의 유일한 window가 되고, 그것에 하나 이상의 Views가 포함됩니다. 그 후 UIWindow는 포함된 Views를 출력하는 역할을 수행하게 됩니다. 아이폰 운영체제가 계층적인 windows를 지원하기는 하지만, 1개가 넘는 window를 생성하지 말라고 경고하고 있습니다.

UIWindow는 닫기 버튼이나 타이틀바와 같은 UI를 제공하지 않습니다. 모든 기능은 프로그래밍으로 정의하여 처리해야 합니다. 이것은 모든 아이폰 어플리케이션이 같은 UI 방법으로 시작과 종료를 하기 위한것으로 아이폰의 바탕화면에서 아이콘을 터치하여 프로그램을 시작하고, 홈 버튼을 눌러서 종료하는 것을 위한 것입니다.

어플리케이션을 생성할 때, window의 초기 사이즈는 화면 사이즈에 꽉 차게 생성됩니다. nid나 코드 모든것을 통해서 window는 화면 사이즈보다 작아질 수 없습니다. 화면 사이즈에 맞는 UIWindow는 다음과 같이 UIScreen 을 이용하여 다음과 같은 코드로 생성할 수 있습니다.

<code>
UIWindow * aWindow = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
</code>

아 이폰 어플리케이션에서 view는 대부분 UIView를 상속받아 만들어집니다. 이것은 사용자의 인터페이스를 출력하고, 인터페이스와 통신하는 중요한 두가지 역할을 수행합니다. 모든 view 오브젝트는 지정된 사각 영역 안에서 출력하고 인터페이스의 이벤트를 처리합니다.

하나의 view는 여러개의 sub view를 관리합니다. sub view의 관점에서 그것을 포함하고 있는 view는 superview 또는 parent view라고 불립니다.  sub view 또한 또 다른 sub view를 포함하여 superview가 되는 계층적 구조를 가지고 있습니다.

아이폰 운영체제는 UIKit 이라는 클래스를 제공합니다. UIKit은 UIView를 이용한  window와 각종 컨트롤(views)을 제공합니다. 정말 다양한 views를 제공하기 때문에 다른 운영체제에서 프로그래밍할 때와는 다르게 새로운 컨트롤을 제작할 일이 거의 없습니다. UI 디자인도 그 무엇보다 훌륭하여, 프로그래머가 디자인에 신경쓰지 않고 기본 컨트롤을 그대로 써도 멋진 프로그램이 될 정도입니다. 다른 운영체제(Window)에서는 그렇지 않았죠.

사용자 삽입 이미지

위 그림에서 보는 것과 같이, 정말 많은 컨트롤이 기본적으로 제공되고 있습니다. 각 컨트롤에 대한 자세한 내용은 각각의 컨트롤을 검색하여 사용해보시면 금방 숙지할 수 있습니다.

UIKit은 기본적으로 top-left 좌표계를 사용합니다. 왼쪽 상단이 0,0으로 아래, 오른쪽으로 갈 수록 숫자가 커지는 방식입니다. 다른 운영체제처럼 정수계를 사용하지 않고, floating 형식, 즉 실수계를 사용합니다. 이것은 더 정확히 위치를 잡을 수 있게 하는것에 많은 도움이 됩니다. 예를 들어 300, 300 사이즈를 1/4 로 줄였다가 다시 4배로 정확히 키울 수 있습니다. 다음 그림은 아이폰 스크린과 좌표계의 관계를 나타냅니다.

사용자 삽입 이미지
모든 View 객체는 크기와 위치 속성을 포함함니다. 크기와 위치를 결정하는 속성으로는 Frame과 Bounds라는 두 가지의 중요한 개념이 있습니다. Frame은 출력되는 화면 영역을 의미하고, Bounds는 출력할 데이트에서의 영역입니다. 아래 그림을 보면 이 개념을 확실하게 이해할 수 있습니다. 왼쪽에 있는 그림 데이터에서 사용할 영역을 지정한것이 Bounds 개념이고, 이 Bounds를 화면 영역의 어느 부분에 출력할 지 결정하는 좌표가 Frame 영역입니다.

사용자 삽입 이미지
또 한가지 속성에 Center 값이 있습니다. 이 값은 Frame 영역에서의 가운데 좌표(X, Y)를 의미합니다. Bounds 영역에서의 Center가 아니라는 점을 꼭 명심하고 있어야, 나중에 개발 할 때 헷갈림이 없을 것입니다.

View 객체가 생성될 때 위 세가지 (Bounds, Frame, Center) 속성이 다음과 같이 초기화 됩니다.
Bounds rectangle 의 원점(Top-Left)를 0, 0으로 설정하고, 가로, 세로를(Width, Height)를 Frame(화면 영역)과 같게 설정합니다. 그리고 Center 속성을 Frame의 width/2, height/2 즉 가운데로 설정합니다. 이 세가지의 속성은 각각을 수정해도 다른 두가지의 속성에 다음과 같이 영양을 끼칩니다.

* Frame 속성을 설정하면 Bounds가 Frame의 사이즈에 맞게 확장됩니다. 그리고 Center 속성이 새로운 Frame에 맞게 변화합니다.
* Center 속성을 설정하면 Frame 속성의 원점이 변경됩니다. 즉, Frame의 크기가 변경되는 것이 아니고 Frame의 가운데를 손가락으로 잡고 움직여서 Frame 자체를 움직이는 듯한 효과가 있습니다.
* Bounds의 사이즈를 변경하면 Frame이 그 크기에 맞춰서 변화합니다.
* Bounds의 원점은 두개의 속성(Frame, Center)의 변경 없이도 바꿀 수 있습니다. 아래 그림과 같이 Bounds의 원점을 대각선 아래로 변경하여 그림의 다른 부분을 똑같은 Frame 에 출력되도록 할 수 있습니다.

사용자 삽입 이미지
이로서 아이폰의 윈도우, 뷰, 좌표계의 개요를 마무리 하겠습니다. 다음 강좌에서는 각 좌표를 변환(회전, 이동, 확대, 축소)등을 수행할 수 있는 방법을 소개하고 실질적으로 실습하는 모습을 보여드리겠습니다.

Posted by Getroot

Leave your greetings.

  1. find cheap <a href="http://www.echeapraybansunglasses.com/"><strong>ray ban aviator</strong></a> products on the <a href="http://www.echeapraybansunglasses.com/"><strong>ray ban sunglasses</strong></a> store, then you can see the fashion <a href="http://www.echeapraybansunglasses.com/"><strong>aviator sunglasses</strong></a>, enjor to buy <a href="http://www.echeapraybansunglasses.com/"><strong>raybands</strong></a> gooo.

    2011/10/20 11:43 [ Permalink : Modify/Delete : Reply ]

iPhone/기획2009/03/05 19:48

이번주에는 매우 간단한 게임 두 가지에 대해서 리뷰하겠습니다. 이 두 가지 게임은  두 손가락을 가지고(한 손으로 해도 됩니다) 속도를 즐기는 게임이라는 공통점을 가지고 있습니다.

그 첫 번째는 2009년 2월 21일 Entertainment 카테고리의 free application 9 위인 Bubble Wrap 이라는 게임입니다. 이른바 사람들이 말하는 일명 뾱뾱이( 에어캡 ) 게임입니다.
 





사용자 삽입 이미지사용자 삽입 이미지

게임을 시작하면 화면에 우리가 종종보던 뾱뾱이(에어캡)들이 자리를 잡고 있습니다. 자, 지금부터 45초 동안 손가락들이 얼마나 빠르게 움직일 수 있는지 내 손가락의 속도를 확인하는 일만 남았습니다.

45초간의 스피디한 손가락 움직임을 보여주었다면 나의 점수를 기록합니다.

사용자 삽입 이미지사용자 삽입 이미지
Bubble wrap은 어릴적에 뾱뾱이(에어캡)가 생기면 장난감 삼아서 놀던, 그 향수를 불러일으키는 그런 게임입니다. 손가락을 얼마나 빠르게 움직이느냐 하는 단순함으로 다가옵니다. 하지만 제가 게임을 즐겼던 환경이 i pod touch 2세대였기 때문인지, 뾱뾱이(에어캡)를 누르는 생동감을 단순히 소리로만 느껴야 한다는 것이 작은 아쉬움으로 남았습니다. 아마도 iPhone 이라던가 국내에 있는 T 옴니아나 햅틱등의 진동이 되는 기기라면 보다 재밌게 즐길 수 있을 것으로 생각 됩니다.

팁을 한가지 드린다면, 터치를 통하여 터진 뾱뾱이(에어캡)가 다시 바람이 들어가는데 시간이 조금 걸리기 때문에 약간씩의 여유를 가지면서 터트려 준다면 높은 점수를 얻을 수 있습니다.


두번째 게임은 Fast finger 입니다.

사용자 삽입 이미지
이 application은 비록 순위에 올라있지는 않지만 Bubble Wrap 과 같이 손가락 빠르기를 테스트하는 게임입니다.
start 버튼을 누르면 아래와 같은 화면이 나오는데  tap 부분을 빠르게 눌러주면 카운트가 됩니다.

사용자 삽입 이미지사용자 삽입 이미지사용자 삽입 이미지
30초 동안 열정적으로 터치를 해 주는 것이 게임의 전부 입니다. 30초가 지나면 몇번 터치가 되었는지 점수가 나오고 restart 를 누르면 다시 게임을 하게 됩니다.

위 게임은 친구들과 내기용으로 한 두번 해 보기에는 유용해 보이지만 게임 중간중간에 자사의 다른 프로그램을 홍보하거나 점수를 기록하는 기능이 없어서 게임에 동기부여가 되지 않아 지속적으로 하기엔 무리가 있습니다.

이번주에 소개한 두 게임 모두 조작이 쉽고 단순함이 매력적이긴 하지만 이런 매력만으로는 게임을 지속하고 다시 찾게하기 어려워 보입니다. Bubble Wrap 의 경우 뾱뾱이(에어캡)가 다시 바람이 들어가는 시간을 줄이거나 점수를 올려주는 보너스 요소를 조금 보강하고, F.finger의 경우는 문지르기를 넣거나 자신의 기록을 남길 수 있는 공간이 생간다면 사용자들로 하여금 보다 재미를 느끼게 해 줄 수 있지 않을까 생각 해 보았습니다.



Posted by 부르주아

Leave your greetings.

iPhone/팁&태크2009/03/05 19:47
아이폰 앱스토어에 자신이 만든 어플리케이션을 올리기 위한 iPhone Developer Program이라고 부르는 개발자 등록 과정에 대해 간단하게 알아보도록 하겠습니다.

http://developer.apple.com/iPhone/program 에 방문하여 Learn More를 클릭하면 곧바로 가입화면을 볼 수 있습니다.
사용자 삽입 이미지
Standard Program과 Enterprise Program 두가지를 보실 수 있는데요, 우리가 알고 있는 일반적인 개발자 프로그램은 Standard Program입니다.

밑의 Enterprise Program의 경우 Adhoc Distribution(예를 들어 택배회사에서 자사의 택배관리 프로그램을 개발하여 아이폰을 전직원들에게 배포할 경우 회사 내부의 배포가 가능해야 겠죠)을 지원하지만 이것이 필요한 회사는 국내실정에선 없을것 같군요.
사용자 삽입 이미지
Standard Program을 선택하더라도 개인(Individual)과 회사(Company)를 선택할 수 있습니다.

회사의 경우 영문 사업자 등록증을 팩스로 보내야 하는 등의 좀더 복잡한 절차가 기다리고 있습니다.

우리는 회사입장에서 진행해 보도록 하겠습니다.
사용자 삽입 이미지
조금 싱겁게 등록이 끝나버렸군요. 몇일후에 애플쪽에서 컨텍을 할테니 iPhone Dev Center 에서 개발 연습이나 하고 있으라는 군요.

사용자 삽입 이미지
약 1주일 전후로 위와 같은 메일이 도착합니다. License Agree를 요청하는 메일이죠.

이후에 따로 회사로 연락이 옵니다. 간단한것 몇가지 묻고 사업자 등록증을 팩스로 보내달라고 합니다.

국제 팩스를 보내셔야 합니다. 필요한 경우 등록한 개발자와 통화를 요청할 때도 있습니다.
사용자 삽입 이미지
제가 Development Kit 구매화면을 캡춰하지 못해 구매완료 화면으로 대신합니다.

이후에 구매 가능한 링크의 주소를 보내줍니다. 99$ 결재하시면 됩니다.
사용자 삽입 이미지
구매 완료후에는 위와같이 Activation 코드를 보내옵니다. 해당 코드로 계정을 활성화 할 수 있습니다.
사용자 삽입 이미지
모든 것이 완료된 이후의 환영 메일이군요^^

Posted by 아이

Leave your greetings.

  1. 방문자

    안녕하세요? 작성해주신 글 잘 보았습니다.
    회사 입장에서 개발자 등록 글을 써주셔서 한가지만 물어볼게요.
    제가 다니는 회사에서도 아이폰 개발자 등록을 하려고 하는데요.
    스탠다드 계정 1개(99$)로 회사 전체 개발자가 계정을 사용할 수 있는것일까요?

    2010/03/11 11:46 [ Permalink : Modify/Delete : Reply ]

iPhone/팁&태크2009/03/05 19:47
   *알려드립니다! 이 게시물은 해킹에 성공한 iPod touch에만 적용되는 것이므로 그렇지 않은 iPod touch유저분들의 오해가 없으시기 바라면서 글을 시작하겠습니다.

   오늘부터 써드파티어플(Cydia 어플리케이션)중 한 가지를 선택해서 소개해드리는 시간을 갖도록 하겠습니다. 이번 시간에는 WinterBoard라는 테마변경 써드파티어플을 소개하겠습니다. WinterBoard는 iPod touch의 테마를 변경시켜주는 써드파티어플 입니다. 자기의 입맛대로 테마를 꾸밀 수 있다는 장점이 있어서 많은 iPod touch 해킹 유저들이 애용하는 써드파티어플 중 한가지이기도 합니다. 자 그럼 다 같이 설치를 시작해 볼까요?

   먼저 다음 그림과 같이 Cydia에서 WinterBoard를 설치합니다.


사용자 삽입 이미지
 
   그리고 컴퓨터와 iPod touch를 연결해주시고 아래의 경로에서 다운받은 TouchExplorer를 실행시켜줍니다. 초기 실행화면은 다음 그림과 같습니다. 단, net framework 2.0 이상이 컴퓨터에 설치되어 있지 않다면 응용 프로그램 오류 창이 뜨니 다음의 경로에서 다운로드 받아 설치해주세요.
TouchExplorer :


net framework : http://download.microsoft.com/download/5/6/7/567758a3-759e-473e-bf8f-52154438565a/dotnetfx.exe


사용자 삽입 이미지

   이제 받아놓은 테마를 해당 경로에 넣을 차례인데요. 아래의 경로로 찾아가봅시다.
   /private/var/stash/Themes.******** (* 표시 되어 있는 부분은 iPod touch마다 다르니 Themes까지 찾아가시면 됩니다.) 받아놓은 테마를 드래그해서 통째로 넣어주시면 됩니다. (만약 압축이 되어 있으면 풀어서 넣어주세요.) 저는 '박보영'씨의 테마를 넣어보았는데요. 아래 그림과 같이 테마가 들어간 걸 보실 수 있습니다. (한글명일 경우 자음과 모음이 분리되지만 신경쓰지 않으셔도 됩니다.)


사용자 삽입 이미지

   '박보영'씨 테마의 폴더로 접근하면 아래와 같이 Icons와 Dock, Wallpaper 3가지로 구성되어 있는 걸 보실 수 있습니다.


사용자 삽입 이미지

   이제 적용을 시켜 볼 차례입니다. Cydia를 통해서 설치한 WinterBoard를 실행시킵니다. 저장한 '박보영'씨 테마를 선택해서 체크해줍니다. 아래 그림까지 되셨다면 Home버튼을 누릅니다.


사용자 삽입 이미지

   Home버튼을 누르고 잠시 대기하면 iPod touch가 새로 Loading되면서 전체적으로 아래 그림처럼 테마가 바뀌어 있는 것을 보실 수 있습니다.


사용자 삽입 이미지

   만약 배경화면을 변경하고 싶으시다면 미리 여러 개의 사진을 넣어둔 뒤에 이름만 Wallpaper로 바꿔주시거나 그때그때 iPod touch를 다시 컴퓨터와 연결하시고 TouchExplorer를 실행시킨뒤에 테마의 경로로 접근하신뒤에 원하는 사진을 넣으시면 됩니다. (jpg사진도 가능하니 참고하세요.)

   지금까지 WinterBoard를 설치하고 테마를 변경하는 과정까지 차례대로 진행해보았습니다. 제가 좋아하는 사람의 사진이나 예쁜 아이콘으로 꾸미니 iPod touch를 더 즐기고 싶은 마음이 들더군요. 갖가지 어플리케이션을 설치해서 써보는 재미도 있구요. 자기만의 iPod touch를 꾸미기 위해 작은 도전을 해보는 것도 좋을 것 같다는 생각이 듭니다. 혹시 진행 과정 중 혼란이 가는 부분이 있다면 추가/수정하도록 하겠습니다. 감사합니다.
Posted by 뽀뎅

Leave your greetings.

iPhone/팁&태크2009/03/05 19:08
Object-C 2.0에 들어 열거형 변수를 좀더 효과적이고 안전하게 사용하기 위해 for 문법이 업그레이드 되었습니다.

이것을 보고 이름하여 Fast Enumeration 이라고 부르는군요. PHP나 Ruby등에서 볼수 있는 foreach와 같은 기능입니다.

일반적인 C에서의 구현에 비해서 매우 편리하게 반복문을 작성할 수 있습니다. 문법은 다음과 같습니다.
// one
for ( Type newVariable in expression ) { statements }

// two
Type existingItem;
for ( existingItem in expression ) { statements }

사용 예제를 보시면 바로 이해가 되실 것입니다. 예제를 보실까요.

NSArray
NSArray *array = [NSArray arrayWithObjects:@"One", @"Two", @"Three", @"Four", nil];
for (NSString *element in array) {
NSLog(@"element: %@", element);
}
// element: One
// element: Two
// element: Three
// element: Four

NSDictionary
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
@"quattuor", @"four", @"quinque", @"five", @"sex", @"six", nil];
NSString *key;
for (key in dictionary) {
NSLog(@"English: %@, Latin: %@", key, [dictionary valueForKey:key]);
}
// English: four, Latin: quattuor
// English: five, Latin: quinque
// English: six, Latin: sex

NSArray - nextObject
NSArray *array = [NSArray arrayWithObjects:@"One", @"Two", @"Three", @"Four", nil];
NSEnumerator *enumerator = [array reverseObjectEnumerator];
for (NSString *element in enumerator) {
if ([element isEqualToString:@"Three"]) {
break;
}
}
NSString *next = [enumerator nextObject];
// next = "Two"

안타깝게도 인덱스가 필요하다면 따로 제공하는것이 없어 다음과 같이 사용하셔야 합니다.
NSArray *array = /* assume this exists */;
NSUInteger index = 0;
for (id element in array) {
NSLog(@"Element at index %u is: %@", element);
index++;
}


예제만으로도 충분히 만족감을 주는 간단한 내용이었습니다.

이글은 http://theeye.pe.kr/entry/Object-C-Fast-Enumeration 에서도 볼 수 있습니다.
Posted by 아이

Leave your greetings.

iPhone/팁&태크2009/03/05 19:08

개발자 프로그램에 등록하였다면 이제 자신의 아이폰(아이팟 터치)에 자신이 만든 어플을 올릴 수 있게 됩니다.

그런데 저는 무언가 간단한 작업이라고 생각했었는데 정말 복잡한 문제더군요.

우선 iPhone Dev Center에 방문하여 로그인을 해봅시다. 예전과는 조금 다른 화면을 보실 수 있습니다.

사용자 삽입 이미지
Apple Developer Forums이라는게 보이는군요. 중요한 Program Portal이라는 것이 오른쪽에 보입니다.

그곳이 아이폰 개발관련 포털 서비스를 제공하는 곳입니다.

1. 개발자 추가 등록

그곳에서 바로 다른 개발자를 등록해 보도록 하겠습니다. Team이라는 메뉴로 들어갑니다.
사용자 삽입 이미지
오른쪽의 Add Member를 클릭하면 사용자를 추가하는 창이 뜨게 됩니다.
사용자 삽입 이미지
이름을 입력하고 Email에는 실제로 초대장이 날라갈 이메일 주소를 적어주시면 됩니다. Role에는 일반 멤버와 관리자를 정할 수 있습니다.

2. 인증서 등록

이번에는 인증서 등록을 위해 Certificates 메뉴로 들어가 봅시다. 아래의 그림에서 표시한 download now를 클릭하여 Apple Worldwide Developer Relations Certification Authority를 설치합시다.
사용자 삽입 이미지
설치시에는 위의 그림과 같이 3가지 모두다 체크를 해줍시다.
사용자 삽입 이미지
이제 개인 키페어를 생성하기 위해 유틸리티 - 키체인 접근 메뉴에 들어갑니다.
사용자 삽입 이미지
키체인 접근 - 인증 지원 - 인증기관에서 인증서 요청
메뉴에 들어갑니다.
사용자 삽입 이미지
위와 같이 체크를 하여줍니다. 사용자 이메일 주소에는 Apple Developer Connection에 등록한 이메일을 공통 이름에는 맥의 내 계정에 등록한 이름으로 동일하게 작성해 줍니다.

CA 이메일 주소는 아무것도 쓰지 않습니다.
사용자 삽입 이미지
키페어 정보는 위와같이 하시면 됩니다. 기본적으로 위와 같이 설정됩니다.
사용자 삽입 이미지
위와 같이 하면 인증서 파일(공개키)이 생성됩니다. 이것을 Certificates 메뉴의 Request Certificate를 눌러 위와같은 화면이 뜨면 파일을 선택하여 등록하여 줍니다.
사용자 삽입 이미지
등록이 되면 ActionApprove가 뜹니다. 그것을 눌러줍니다.
사용자 삽입 이미지
위의 그림과 같이 Download버튼이 생겨납니다. 해당 버튼을 누르면 생성된 나만을 위한 인증서를 다운받을 수 있습니다.
사용자 삽입 이미지
다운받은 인증서를 추가합니다. 키체인에는 로그인만 있으면 됩니다.
사용자 삽입 이미지
잘 추가되었군요. iPhone Developer : 이름이 추가되어있으면 정상적으로 된것입니다.

3. Device 등록

이제 XCode에서 Windows - Organizer를 띄웁니다. 연결했던 나의 아이팟 정보가 뜨게 됩니다. 선택해 봅시다.
사용자 삽입 이미지
위와 같이 Identifier에 40자리의 Hex 코드가 있습니다. 그것을 복사합니다.
사용자 삽입 이미지
Device 메뉴에 들어가서 Add Devices를 클릭합니다. 위와 같은 화면에서 디바이스의 명칭을 정하고 Device ID에는 아까 복사한 40자리 코드를 붙여넣기 합니다.

4. App ID 등록

이제 App ID를 등록할 차례입니다. 이곳에서 많은 분들이 헤매시고, 저역시고 헤매었고; 어려운 부분입니다.
사용자 삽입 이미지
App ID Name
에는 그냥 Program Portal에서 사용하는 식별자라고 생각하시면 됩니다. 별 의미 없으니 뒤의 Identifier에 지정할 내용의 별칭을 지정해 주시면 됩니다.

뒤의 App ID가 조금 중요한 부분인데, Bundle Seed IDBundle Identifier를 합쳐서 App ID가 되게 됩니다.

Bundle Seed ID는 자동 생성 되는것이므로 신경 쓰지 마시고 Bundle Identifier가 중요한데요.

보통은 도메인을 뒤집어 사용합니다. apple.com의 경우 com.apple.*을 사용하게 됩니다.

이는 com.apple 이하의 모든 Bundle Identifier를 허가한다는 뜻입니다. 이런 설정이 귀찮으시다면 *하나만 달랑 써주시면 어떤 경로던지 허가가 되게 됩니다.
사용자 삽입 이미지
등록이 완료된 모습입니다. ID에 보면 XXXXXX.com.apple.* 과 같이 등록된 것을 알 수 있습니다.

여기서 중요한것은 어플리케이션을 만들때 앞의 XXXXXX부분의 코드를 사용하지 않는다는 것입니다.

5. Provisioning 등록
이제 Provisioning을 설정할 때입니다. 공급쯤으로 이해하면 될까요?
사용자 삽입 이미지
Profile Name
을 정하고 자신에게 해당하는 인증서와 생성해둔 App ID 및 등록했던 Device를 선택합니다.
사용자 삽입 이미지
이제 거의 마무리 단계군요. 이제 지금까지 생성했던 나의 계정 + 인증서 + 디바이스 + App ID가 모두 짬뽕된 Provisioning Profile을 다운 받을 수 있습니다.
사용자 삽입 이미지
이 다운 받은 파일을 Organizer 창의 Provisioning 부분에 드래그하여 끌어다 놓습니다.

6. 내 아이폰(아이팟 터치)에 프로그램 올려보기

사용자 삽입 이미지
XCode에서 보시다 시피 왼쪽 위의 창을 Device로 바꿔 줍니다. 그리고 Group&Files창의 프로젝트명을 선택한 상태에서 오른쪽 위의 Info를 클릭합니다.
사용자 삽입 이미지
Build
탭에서 Code Signing Identity의 하위 메뉴인 Any iPhone OS Device에서 내가 등록한 Provisioning Profile을 선택합니다.
사용자 삽입 이미지
Info.plist
파일을 열어 Bundle identifier부분을 App ID에서 등록했던 내용으로 수정하여 줍니다.

App IDXXXXXX.com.apple.* 이었다면 com.apple로 시작하는 어떤 값의 Identifier도 가능하다는 뜻입니다.

위의 값으로는 com.apple.${PRODUCT_NAME:identifier} 로 하면 자동으로 com.apple.HelloWorld(프로젝트명) 가 사용되게 됩니다.
사용자 삽입 이미지
참고로 위의 창을 띄우기 위해서는 Targets안의 내 프로젝트 명을 더블 클릭하여도 됩니다.

이제 마지막으로 실행을 위해 Build&Go를 클릭하면 내 디바이스에 업로드 되어 실행되는 것을 볼 수 있습니다.

* 마치며

위와 같은 과정을 거쳤음에도 인증 문제를 만나는 경우가 있었습니다.

보통은 App ID와 프로젝트의 Bundle Identifier가 불일치 해서 오는 문제였으며 이 문제는 인증서 부분과 App ID등록 부분을 잘 해보면 해결이 되는 문제입니다.

하지만 모든것이 완벽하여 XCode상에서 에러가 발생하지 않지만 인증 문제를 내뱉는 경우가 있습니다.

이때는 공장초기화를 해주고 아이튠즈에 다시 싱크를 해주니 잘 되더군요. 최악의 경우에는 초기화를 해보시기 바랍니다.

새로운 개발자를 등록하였다면 어떻게 해야 할까요?

위의 과정에서 1, 2, 3, 5를 반복하여 Provisioning Profile을 생성해 주면 됩니다.

App ID를 아무래도 같은 팀이라면 공유하는게 좋겠죠.

Posted by 아이

Leave your greetings.

iPhone/강좌2009/03/05 19:08
iPhone OS에서 실행되는 어플리케이션은 Core OS와 Core Services 프레임워크를 분류하여 로컬 파일시스템과 네트워크에 접근할 수 있습니다.

또한 사용자의 데이터를 저장하거나 다음 사용을 위한 어플리케이션의 상태를 저장하기 위해 파일을 읽고 쓰는 것이 가능합니다.

네트워크에 접근함으로써 네트워크상의 서버와 통신하거나 데이터를 주고 받는 등의 원격 작업을 수행할 수 있는 기능을 갖출 수 있습니다.

iPhone OS의 파일은 사용자들의 미디어파일과 개인정보와 같은 파일들과 함께 Flash 메모리를 공유하여 사용하고 있습니다.

보안상의 이유로 개발자가 만든 어플리케이션은 자신이 위치한 자신의 디렉토리에 국한하여 제한적인 데이터 읽기, 쓰기만을 할 수 있습니다. 

Commonly Used Directories

보안을 위해 어플리케이션은 몇몇에 불과한 디렉토리에 접근하여 데이터와 환경 설정을 읽고 쓸수 있습니다.

어플리케이션이 장치에 설치될때 어플리케이션을 위한 홈 디렉토리가 생성됩니다.

다음은 그 내부의 중요한 서브디렉토리의 설명입니다.

<Application_Home>/AppName.app

이 디렉토리는 어플리케이션 자신을 포함하는 Bundle 디렉토리입니다.
실행중에 이 디렉토리 내부의 파일을 변경할 수 없습니다.
iPhone OS 2.1 혹은 그 이후의 버젼은 iTunes에서 이 디렉토리를 백업하지 않습니다.
그러나 어플리케이션을 구매했을 당시의 초기 싱크 과정에서는 컨텐츠 내용이 복사됩니다.

<Application_Home>/Documents/

이 디렉토리는 어플리케이션이 특정 데이터를 저장하기 위해 사용되는 공간입니다.
사용자의 데이터나 다른 정보를 정기적으로 저장할 수 있습니다.
이 디렉토리 내부의 컨텐츠는 iTunes에 의해서 백업 됩니다.

<Application_Home>/Library/Preferences

이 디렉토리는 어플리케이션의 특정 설정 파일을 포함합니다.
하지만 환경 설정 파일을 직접 생성하여서는 안되고 NSUserDefaults 클래스나 CFPreferences API를 사용해야 합니다.
이 디렉토리 내부의 컨텐츠는 iTunes에 의해서 백업 됩니다.

<Application_Home>/Library/Caches

이 디렉토리는 어플리케이션의 실행때마다 지속적으로 사용해야 하는 파일을 읽고 쓰기 위해 사용합니다.
개발한 어플리케이션은 일반적으로 이곳에 파일을 추가하고 삭제하여야 합니다.
iTunes는 전체 복원시에 이 디렉토리의 내용을 모두 제거 합니다.
그러므로 어플리케이션은 필요할때마다 이곳의 파일을 생성해 낼 수 있어야 합니다.
iPhone OS 2.2 혹은 그 이후의 버젼은 iTunes에서 이 디렉토리를 백업하지 않습니다.

<Application_Home>/tmp/

이 디렉토리는 어플리케이션이 실행때마다 지속될 필요가 없는 임시적인 파일을 읽고 쓰기 위해 사용합니다.
어플리케이션이 실행중이 아닐때 시스템은 파일이 더 필요한가를 판단하여 더이상 필요하지 않다고 판단이 되면 삭제합니다.
iPhone OS 2.1 혹은 그 이후의 버젼에서는 iTunes에서 이 디렉토리를 백업하지 않습니다.

Backup and Restore

어플리케이션이 백업과 복원을 위해 따로 준비해야 하는 것은 없습니다.

iPhone OS 2.2 혹은 그 이후의 버젼은 장치가 컴퓨터에 연결되어 싱크 될때 다음을 제외한 나머지 모든 파일을 증분 백업 합니다.
<Application_Home>/AppName.app
<Application_Home>/Library/Caches
<Application_Home>/tmp

어플리케이션이 매우 큰 파일을 생성하거나 매우 빈번하게 파일 엑세스를 한다면 /Documents가 아닌 /Library/Caches를 이용하는 것이 좋습니다. /Documents에 저장하게 되면 백업/복원 작업시에 시간이 더 걸리게 되는 문제점이 될 수도 있습니다.

Getting Path to Application Directories

다양한 레벨의 시스템에서 어플리케이션의 샌드박스의 위치를 알아내기 위한 다양한 프로그래밍 방식이 있어왔습니다.

하지만 Cocoa는 이러한 경로를 탐색하기 위해 다양한 프로그래밍 인터페이스를 제공합니다.

NSHomeDirectory(Foundation 프레임워크에 포함) 함수는 홈디렉토리의 경로뿐만 아니라 Documents, Library 그리고 tmp같은 디렉토리 경로를 손쉽게 얻어올수 있습니다.

또한 추가적으로 NSSearchPathForDirectoriesInDomains와 NSTemporaryDirectory함수를 사용하여 정확한 Document, Caches, tmp 디렉토리 경로를 얻어올 수 있습니다.

이 NSSearchPathForDirectoriesInDomains 함수를 사용하여 어플리케이션과 연관된 전체 경로를 알 수 있습니다.

iPhone OS에서 이 기능을 사용할려면 적절한 검색 경로를 첫번째 매개 변수로, NSUserDomainMask를 두번째 매개 변수로 지정합니다.

일반적으로 자주 사용되는 경로 상수는 다음과 같은 것들이 있습니다.

NSDocumentDirectory
<Application_Home>/Documents

NSCachesDirectory
<Application_Home>/Library/Caches

NSApplicationSupportDirectory
<Application_Home>/Library/Application Support


어플리케이션의 Documents/ 디렉토리를 찾기 위해 다음과 같이 사용합니다.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];

위의 결과값을 찍어보면 /var/mobile/Applications/해쉬코드/Documents 와 같은 값이 나옵니다. 해당 경로가 어플리케이션 Documents 디렉토리의 절대 경로가 되겠죠.

두번째 인자인 NSUserDomainMask말고 다른것을 사용할 수 있습니다.

NSSystemDomainMask와 첫번째 인자로 NSApplicationDirectory로 검색하여 보면 /Applications 라는 시스템 경로를 얻을 수 있습니다.

Reading and Writing File Data

iPhone OS는 파일을 읽고 쓰고 관리할 수 있도록 몇가지 방법을 제공하고 있습니다.

Foundation Framework :
  • 어플리케이션이 Property List를 사용한다면 NSPropertyListSerialization API를 사용하여 NSData로 변환이 가능합니다.  이렇게 변환 후에 NSData의 메서드를 이용하여 데이터를 쓸 수 있습니다.
  • 어플리케이션의 Model객체가 NSCoding 프로토콜을 채택하였다면 NSKeyedArchiver 클래스를 이용하여 객체를 저장할 수 있습니다.
  • Foundation 프레임워크는 컨텐츠 파일의 랜덤 엑세스를 위한 NSFileHandle 클래스를 제공합니다.
  • Foundation 프레임워크안의 NSFileManager는 시스템에 있는 파일을 생성하고 조작하는 메서드를 제공합니다.

Core OS calls :

  • fopen, fread, fwrite 를 호출하여 데이터를 엑덤 엑세스를 통해 읽고 쓸 수 있습니다.
  • mmap과 munmap을 호출하여 효과적으로 큰 파일을 메모리로 로드하거나 그안의 컨텐츠에 접근할 수 있습니다.

Reading and Writing Property List Data

Property List는 캡슐화 되어있는 데이터를 말합니다. 배열, 문자열, 날짜, 이진데이터, 숫자 및 Boolean 값을 포함합니다.

다른 예로 모든 Cocoa/iPhone 어플리케이션의 설정이 들어있는 Info.plist 파일을 들 수 있습니다.

코드상에서는 NSDictionary, NSArray, NSString, NSDate, NSData, NSNumber를 사용할 수 있습니다.

다음은 Property List를 NSData로 변환하여 저장하는 방법입니다.

- (BOOL)writeApplicationPlist:(id)plist toFile:(NSString *)fileName {
NSString *error;
NSData *pData = [NSPropertyListSerialization dataFromPropertyList:plist
format:NSPropertyListBinaryFormat_v1_0 errorDescription:&error];
if (!pData) {
NSLog(@"%@", error);
return NO;
}
return ([self writeApplicationData:pData toFile:(NSString *)fileName]);
}
- (BOOL)writeApplicationData:(NSData *)data toFile:(NSString *)fileName {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
if (!documentsDirectory) {
NSLog(@"Documents directory not found!");
return NO;
}
NSString *appFile = [documentsDirectorystringByAppendingPathComponent:fileName];
return ([data writeToFile:appFile atomically:YES]);
}

그러면 읽어와야 겠죠. 다음의 코드를 참고하세요.
- (id)applicationPlistFromFile:(NSString *)fileName {
NSData *retData;
NSString *error;
id retPlist;
NSPropertyListFormat format;
retData = [self applicationDataFromFile:fileName];
if (!retData) {
NSLog(@"Data file not returned.");
return nil;
}
retPlist = [NSPropertyListSerialization propertyListFromData:retData
mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&error];
if (!retPlist){
NSLog(@"Plist not returned, error: %@", error);
}
return retPlist;
}
- (NSData *)applicationDataFromFile:(NSString *)fileName {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *appFile = [documentsDirectory stringByAppendingPathComponent:fileName];
NSData *myData = [[[NSData alloc] initWithContentsOfFile:appFile] autorelease];
return myData;
}

id는 객체 자신을 가리키는 타입입니다. 무엇이든 가리킬 수 있는 자바의 Object라고 생각하시면 이해가 쉬울까요.

Using Archivers to Read and Write Data

실제로 프로그램이 실행할때 메모리에 수많은 객체를 생성합니다. 그리고 각각의 객체는 서로 연결되어있습니다.

이러한 객체를 파일로 저장후에 다시 읽었을때 연결된 다른 객체가 존재하지 않는다면 큰 문제가 되겠죠.

아카이브라 불리는 이 과정은 실행중에 생성된 객체들의 복잡한 상속관계를 나타내는 그래프를 모두 바이트 단위로 변환하는 과정입니다.

이것을 사용하기 위해서는 클래스가 NSCoding을 구현해야 하고 그에 따른 encodeWithCode와 initWithCoder 메서드를 구현해야 합니다.

자세한 내용은 관련 [문서]를 참고하세요. 데이터를 저장하기 위해서는 다음과 같은 방식으로 합니다.
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:[_myDataSource representation]];
[data writeToFile:myFilePath atomically:YES];

데이터를 읽어 들여 복원할때는 다음과 같이 하면 됩니다.
NSData* data = [NSData dataWithContentsOfFile:myFilePath];
id rootObject = [NSKeyedUnarchiver unarchiveObjectWithData:data];

File Acess Guidelines

파일을 생성하고 데이터를 쓸때 다음의 가이드 라인을 지키도록 합시다.

파일을 쓰는 횟수를 최소화 해야 합니다. 파일을 엑세스 하는 작업은 느리고 제한적인 수명을 가진 플래시 메모리에 하는 행위입니다.

  • 파일의 일부분이 변경되었을때 바뀐 부분만을 쓸 수 있습니다. 적은 바이트의 변경을 위해 전체 파일을 쓰는 행위를 피하도록 합시다.
  • 파일 포맷을 정의할때, 자주쓰이는 데이터를 최대한 하나의 그룹으로 묶어 저장하면 디스크 엑세스 횟수를 최소화 할 수 있습니다.
  • 랜덤한 엑세스가 필요한 데이터 구조로 되어있는 경우 SQLite 데이터베이스에 데이터를 저장할 수 있습니다.

캐쉬 파일을 디스크에 쓰는것을 피하도록 합니다. 어플리케이션이 종료될때 다음 실행시에 동일한 상태로 시작하기 위해 저장하는 것은 예외로 합니다.

Saving State Information

사용자가 Home 버튼을 누르게 되면 iPhone OS는 당신의 어플리케이션을 종료하고 홈스크린 화면으로 돌아갑니다.

마찬가지로 URL을 여는 경우 어플리케이션이 종료하고 다른 어플리케이션의 URI가 열리게 됩니다.

이 과정은 멀티테스트 환경과 달리 현재 실행되는 어플리케이션이 종료되고 다른 어플리케이션이 수행되는 것을 뜻합니다.

이러한 작업이 자주 일어난다면 어플리케이션의 상태를 관리하는 방법을 변경할 필요가 있습니다.

사용자가 수동으로 디스크에 저장하는 작업과 달리 주요 지점에서 자동으로 저장하도록 프로그램이 변경되어야 합니다.

어플리케이션이 종료될 때 임시 캐시 파일이나 데이터베이스 환경을 이용하여 상태를 저장해야 합니다.

다음에 어플리케이션이 실행될때 저장되었던 정보를 가지고 이전 상태로 복원하는 과정을 수행하여야 합니다.

저장하는 횟수를 최소화 하여야 하지만 최대한 적절한 시점에 저장하여 이 상태를 그대로 복원하여 보여주어야 합니다.

예를 들어 연락처를 수정하고 있다가 어플리케이션을 종료하고 다시 실행했을 때 연락처의 가장 첫화면보다 수정하던 창을 그대로 보여주는 것이 좋습니다.

Networking

iPhone OS의 네트워킹 스택은 아이폰과 아이팟 터치에 있는 무선 하드웨어 장치의 여러 인터페이스를 포함합니다.

주요 프로그래밍 인터페이스로는 BSD소켓으로 만들어진 CFNetwork 프레임워크가 있습니다.

이 문서에서는 간략한 조언만을 담고 있고 NSStream 클래스를 사용하는 방법의 정보를 원하시면 Foundation Framework 문서를 참고하시기 바랍니다.

Tip for Efficient Networking
네트워크를 통해 데이터를 주고받는 행위는 장치의 많은 전력을 소비하는 행위라는것을 기억하셔야 합니다.
데이터를 주고받는 시간을 최소화 하는 것이 배터리 수명에 도움이 됩니다.

  • 통신 프로토콜을 정의할때 데이터 포맷은 가능한한 작게 만들어야 합니다.
  • 채팅과 같은 무수히 많은 통신이 오가는 방식은 피하도록 합니다.
  • 데이터는 하나의 덩어리로 묶어 보낼 수 있습니다.

Cellular와 Wi-Fi를 이용한 통신은 아무런 행동이 없을때 파워가 꺼지도록 만들어져 있습니다. 하지만 계속해서 작은 용량의 패킷을 주고 받게 되면 이것은 지속적으로 파워가 켜져있게 되는 것을 의미하게 되며 배터리가 소모된다는 것을 뜻합니다.

그러므로 작은 데이터를 자주 주고 받는것보다는 큰 데이터를 긴 시간차를 두고 주고 받는 것이 좋습니다.

네트워크를 이용한 통신 프로그램을 작성할때는 패킷의 손실이 일어날 수 있다는 것을 기억해 두어야 합니다.

코드를 작성할때 통신 실패에 대한 핸들링을 충분히 하여야 합니다.

그 예로 네트워크가 갑자기 사라지게 될 경우 사용자에게 알리는 시스템을 갖추는 등의 노력이 필요합니다.

Posted by 아이

Leave your greetings.

iPhone/팁&태크2009/02/14 04:05
Object-C는 아이폰 개발에 사용되는 언어입니다.

C와 C++의 중간 개념이라고들 하던데 확실히 C언어에 객체의 개념을 추가하고 적절한 라이브러리가 추가된 모습이더군요.

공부하면서 한번 정리를 해보도록 하겠습니다.

객체를 생성하기 위해 클래스를 선언하는데 일반적으로 C++을 해보셨던 분들이 이해하기 좀 어려운 모습을 가지고 있습니다.

XCode에서 New -> New File 항목에서 Object-C Class를 선택하여 클래스 파일을 추가합니다.

Foo 라는 클래스를 만들어 보면 Foo.h와 Foo.m 파일이 생성됩니다.

Foo클래스에 변수와 메서드들을 추가해 봅시다. 다음과 같은 방법으로 합니다.

Foo.h
@interface Foo : NSObject {
IBOutlet NSTextField *textField;
}
- (IBAction)seed:(id)sender;
- (IBAction)generate:(id)sender;
@end

Interface라는 이름을 가지고 선언하긴 하지만 엄연히 클래스를 선언하는 구문입니다.

Foo라는 클래스는 NSObject를 상속받았습니다. NSObject는 NextStep에서 만든 최상위 클래스입니다.

모든 NS로 시작하는 클래스들은 모두 최상위로 NSObject를 상속받습니다. 마치 자바의 Object와 같네요.

또한 NSTextField형의 textField라는 이름의 인스턴스변수(맴버변수)를 선언하였습니다.

IBOutlet은 외부의 다른 객체를 가리킬수 있는 변수를 뜻합니다.

추후에 올려보겠지만 UI상의 컴포넌트 객체들과 변수를 연결할 수 있습니다.

또한 -로 시작하는 줄들은 메서드들입니다. seed메서드만 보면 IBAction을 반환하고 id타입의 sender를 첫번째 인자로 입력 받습니다.

위의 클래스를 구현하면 다음과 같이 합니다.

Foo.m
@implementation Foo

- (IBAction)seed:(id)sender {
...
}
- (IBAction)generate:(id)sender {
...
}

위와 같이 메서드의 몸체를 구현할때 맴버 인스턴스 변수인 textField에 마음껏 접근할 수 있습니다.

객체 자기 자신을 가르킬 경우에는 자바나 C++에서는 this를 사용하지만 여기서는 self를 사용합니다.

인자를 받을 넘길때도 특이한점이 있군요. 두개 이상의 인자를 받을경우에는 굉장히 복잡해 집니다.
- (int)addNumbers:(int)left rightNumber:(int)right {
return left + right;
}

위와 같은 메서드는 addNumbers:rightNumber: 라고 부릅니다. 보통의 프로그래밍을 하던 느낌으론 굉장히 의문이 가는 부분입니다.

addNumbers는 int형 값을 반환하는 메서드입니다. 첫번째 인자는 int형 left 변수입니다.

그렇다면 rightNumber는 저게 뭘까요.  보통 인자를 가진 메서드를 셀렉터(Selector)라고 부릅니다.

위의 코드를 이렇게 바꿔 보면 이해가 쉬울것 같네요.
int addNumbers(int left, int right) {
return left + right;
}

실제로 사용되는 인자의 이름은 left, right이지만 rightNumber와 같은 식의 나누어진 셀렉터를 사용하여 메서드의 인자의 역할을 더욱 분명히 할 수 있는 장점(?)이 있습니다.

이제 함수를 호출하는 방법을 알아보겠습니다.
NSMutableArray *array = [NSMutableArray alloc];

Object-C에서 메서드 호출을 메세지를 보낸다고 표현합니다. 위의 경우에는 다음과 같이 생각하시면 될 것 같네요.
NSMutableArray array = new NSMutableArray();

위와 같이 동적으로 메모리를 잡고 array변수로 가리키게 합니다. 이제 초기화 하는 init 메세지를 보내보겠습니다.
NSMutableArray *array = [NSMutableArray alloc];
[array init];

array는 리시버(receiver)라고 합니다. 이 리시버에 init메세지를 입력합니다.

다음과 같이 위의 두줄을 한줄로 사용할 수도 있습니다.
NSMutableArray *array = [[NSMutableArray alloc] init];

인자를 입력할 경우에는 다음과 같이 사용합니다.
[array addObject:foo];

다수의 인자를 입력할때는 다음과 같은 방법으로 합니다.
[array insertObject:foo atIndex:bar];

위에서 언급했듯이 insertObject는 메서드명이기도 하면서 변수를 가리키는 셀렉터이기도 합니다.

Posted by 아이

Leave your greetings.

iPhone/강좌2009/02/13 16:23
Event Handling

iPhone의 운영체제는 기본적으로 멀티 터치를 지원합니다. iPhone은 기존에 사용자가 이용하던 마우스나 키보드를 벗어나, 화면에 보이는 객체를 자유 자재로 선택하여 조작할 수 있는 환경을 제공합니다. 이러한 터치 이벤트는 다음과 같이 크게 3가지로 분류되어 view에서 메시지를 수신하여 처리할 수 있습니다.

* touchesBegan
prototype:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
설명:
사용자가 화면에 손가락을 대면 호출됩니다.

* touchesEnded
prototype:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
설명:
사용자가 화면에서 손가락을 떼면 호출됩니다.

* touchesMoved
prototype:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
설명:
사용자가 화면에 손가락을 대고 드래그 동작을 하면 호출됩니다.

iPhone에서위와 같은 이벤트가 호출되는 순서를 그림으로 나타내면 다음과 같습니다.

사용자 삽입 이미지

사용자가 손가락 1개를 화면에 터치 하였을 때 UITouchPhaseBegan, 즉 touchesBegan 메시지를 수신하고 또 다른 손가락이 터치 되었을 때 다시 한번 touchesBegan 메시지가 수신됩니다. 이 상태에서 손가락을 떼지 않고 확대/축소를 하기 위해 움직이면 UITouchPhaseMoved, 즉 touchesMoved 메시지가 수신되고 마지막으로 손가락을 떼면 UITouchPhaseEnded, 즉 touchesEnded 메시지가 수신됩니다.

각각의 이벤트는 1-touch와 n-touch 모두 동일하게 발생 되며, UIControl을 상속받아 구현된 UIButton이나 UISlider등의 컨트롤은 이미 이러한 터치 이벤트를 처리하고 있기 때문에 개발자가 기본적인 기능만을 이용한다면 위의 이벤트를 처리할 필요가 없습니다. 하지만, Safari나 Google map같이 페이지를 확대/축소 하거나 위/아래로 이동하기 위해서는 해당 view에서 터치 이벤트를 수신하여 처리하여야 합니다.

HAN
위와 같은 이벤트를 처리하기 위해서는 UIView 클래스를 상속받은 View 클래스를 생성하고 그 클래스 안에서 메시지를 받아서 처리하여야 합니다. 이러한 동작을 하는 프로젝트를 생성하는 방법은 다음과 같습니다.

1. "Xcode"를 실행한 뒤 새 프로젝트를 생성합니다.

2. 다음 그림과 같이 "New Project" 창에서 "Windows-Based Application"을 선택한 뒤 "Choose" 버튼을 누릅니다.

사용자 삽입 이미지


3. 이번엔 생성하고자 하는 프로젝트 이름을 입력합니다. 여기서는 "EventHandling" 이라는 이름으로 프로젝트를 생성하겠습니다.

사용자 삽입 이미지


4. 아래 그림은 "Windows-Based Application"으로 생성된 가장 기본적인 응용 프로그램의 모습입니다. 이 중 "MainWindow.xib" 파일은 View나 기타 화면에 관련된 리소스를 포함하고 있는 파일이며, 새로운 View 클래스를 생성하기 위해 이 파일을 더블클릭 하여 "Interface Builder"를 실행합니다.

사용자 삽입 이미지


5. 다음은 "Interface Builder"의 모습입니다. 새로운 View를 추가하기 위해 "Library" 도구 창의 "View"를 드래그 하여 "Window"창으로 드랍 합니다.

사용자 삽입 이미지


6. View 의 위치가 "Window"안에 꽉 차도록 적당히 레이아웃을 배치합니다.

사용자 삽입 이미지


7. 이번에는 새로 생성된 View에 label을 추가합니다. View와 마찬가지로 "Library" 도구 창의 "Label"을 드래그 하여 "Window" 창으로 드랍 합니다.

사용자 삽입 이미지


8. "Label"을 "Window" 창으로 드랍한 뒤의 모습입니다.

사용자 삽입 이미지


9. "Label"의 위치와 "Text"값을 통해 내용을 수정합니다. 또한 Baseline, Layout 등을 통해 정렬 상태를 변경할 수 있습니다.

사용자 삽입 이미지


10. 이번에는 실제 코드에 사용될 UIView 클래스를 상속받은 View를 생성하기 위해 View의 클래스 이름을 변경합니다. "Window"창의 View를 선택한 뒤 "MyUI View Identity" 도구 창(4번째 탭)의 "Class"에 생성하고자 하는 클래스 이름을 입력합니다. 여기서는 "MyUIView"를 입력하였습니다.

사용자 삽입 이미지


11. 이번에는 "Label"을 코드와 연결하기 위한 선언을 합니다. "MyUI View Identity" 도구 창(4번째 탭)에서 "Class Outlets"의 하단에 있는 "+" 버튼을 눌러 새로운 항목을 생성하고, 해당 항목의 "Outlet"을 지정합니다. 여기서는 "helloLabel"를 입력하였습니다. 또한 이 항목의 데이터 형을 "UILabel"로 지정하기 위해 오른쪽 "Type"에 "UILabel"이라고 입력합니다.

사용자 삽입 이미지


12. 여기까지 작업이 완료되었다면, label과 실제 UI 상의 객체와 매핑 하는 일이 남았습니다. "MyUI View Connections" 도구 창(2번째 탭)에서 "Outlets"에 있는 "helloLabel"의 오른쪽 원 가운데를 드래그 하여 "Window"창의 "Label" 객체에 드래그 합니다. 아래 그림과 같이 드래그 중에 매핑 될 객체의 정보가 간단히 툴팁으로 표시됩니다.

사용자 삽입 이미지


13. 모든 작업이 완료된 후의 모습입니다.

사용자 삽입 이미지


14. 지금까지 작업한 내용을 저장합니다.

사용자 삽입 이미지


15. 저장한 결과를 바탕으로 실제 클래스 파일을 생성하기 위해 "Window"창의 "View"를 선택한 후 메뉴의 "File"-"Write Class Files..."를 선택합니다.

사용자 삽입 이미지


16. 기본적으로 위에서 입력한 "MyUIView"가 표시됩니다. 만약 윗 단계에서 "View"를 선택하지 않으면 다른 클래스를 저장하는 창이 나옵니다.

사용자 삽입 이미지


17. 생성한 클래스를 현재 프로젝트에 추가할 것인지 선택합니다. 사용할 예정이기 때문에 체크한 뒤 "Add"를 눌러 추가합니다.

사용자 삽입 이미지


18. 모든 UI 작업이 끝났으므로 "Interface Builder"를 종료합니다.

사용자 삽입 이미지


19. 최종적으로 생성된 UI 코드 입니다.

사용자 삽입 이미지


위의 방법으로 생성된 코드를 이용하여 터치 이벤트를 핸들링 하는 예제를 작성하여 보겠습니다.

자동으로 생성된 클래스의 부모 클래스를 지정하기 위해 "MyUIView.h"에서 다음과 같이 주석처리 되어 있는 부분을 수정합니다. 또한, 이벤트 처리를 위한 함수를 추가합니다.

@interface MyUIView : /* Specify a superclass (eg: NSObject or NSView) */ {
IBOutlet UILabel *helloLabel;
}

@end


@interface MyUIView : UIView {
IBOutlet UILabel *helloLabel;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;

@end


또한, 이벤트 핸들링을 수행하는 함수를 "MyUIView.m" 파일에 추가하고 각각의 함수를 채웁니다.

#import "MyUIView.h"

@implementation MyUIView

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
helloLabel.text = @"Began";
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
helloLabel.text = @"Ended";
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
helloLabel.text = @"Moved";
}

@end


위 코드에서는 각각의 이벤트가 발생하면 "helloLabel"의 Text를 바꿈으로써 알 수 있도록 하였습니다.
이제 코드를 컴파일 한 뒤 실행하면 터치/드래그 할 때마다 Label의 텍스트가 변경하는 것을 볼 수 있습니다.

여기에서 좀 더 확장하여 터치 후 드래그시 Label이 드래깅 되는 부분을 따라다니도록 수정 해보겠습니다. "touchesMoved" 함수를 수정하여 원하는 기능을 수행할 수 있습니다.

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
helloLabel.text = @"Moved";

UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:self];

CGRect labelPosition = [helloLabel frame];

labelPosition.origin.x = currentTouchPosition.x;
labelPosition.origin.y = currentTouchPosition.y;

[helloLabel setFrame:labelPosition];
}


위와 같이 수정한 뒤 iPhone 에뮬레이터를 실행하면 드래그 할 때마다 Label의 위치가 변경되는 것을 볼 수 있습니다.



사용자 삽입 이미지

아래는 본 실습에 사용된 코드 입니다.


Posted by AccessDenied

Leave your greetings.

iPhone/강좌2009/02/13 14:03
아이폰 어플리케이션 개발이 많은 이슈가 되고 있고, 개발자들의 관심이 날로 증가하고 있습니다. 저희 아이렌소프트도 현재 아이폰 어플리케이션 개발에 착수하였습니다. 이에 아이폰 어플리케이션에 대한 공부를 시작하고 있는데, 이를 내부적으로만 사용하기 보다는 여러 개발자분들과 함께 토론하며 같이 성장하자는 의미에서 앞으로 공부하며 나오는 산출물들을 공개하기로 하였습니다. 첫번째로 애들에서 제공하는 문서인 iPhone Application Programming Guide 를 이용하여 공부하는 내용을 챕터벌로 올릴 예정입니다. 그리고 중간중간 저희가 먼저 삽질했던 부분을 정리하여 팁 & 태크 형식으로 올릴 것 입니다. 또한 기획인 관점에서 인기있는 아이폰 어플리케이션의 리뷰를 진행할 것이며, 아이폰에 대한 새로운 소식을 접하게 되면 그것들을 소개드릴 것 입니다. 아무쪼록 많은 개발자와 기획자 분들도 동참하시어 서로 정보를 공유하며 함께 많은 발전 이루기를 진심으로 기원해봅니다. 아이폰의 한국 출시가 거의 확정되어 있는 상황에서 아이폰 커뮤니티로 발전해 나가길 바랍니다. 먼저 아이폰의 Core에 대해 소개해 드리겠습니다.
 
The Core Application


모든 아이폰 어플리케이션은 UIKit 프레임워크를 사용하여 만들어집니다. 그러므로 모든 아이폰 어플리케이션의 코어(Core)는 같은 구조를 가지고 있습니다. 이것은 대부분의 운영체제가 제공하는 방식이므로 크게 특별한 부분은 없습니다. 윈도우는 MFC나 Windows API를 제공한다는 것과 리눅스 또한 Linux API를 이용하여 프로그래밍 한다는 것과 같습니다.

Core Application Architecture

어플리케이션이 동작한 순간부터 끝날때까지 UIKit 프레임워크는 어플리케이션의 주요 구조의 대부분을 관리합니다. 아이폰 어플리케이션은 시스템으로 부터 계속 이벤트를 받아서 응답합니다. 이벤트를 받는것은 UIApplication 오브젝트의 역할입니다. 하지만 이벤트에 대한 응답은 사용자가 작성하는 코드에서 이루어집니다. 어디서 이벤트에 대한 응답을 할 것인지를 이해하기 위해서는 life cycle과 event cycle에 대한 이해가 필요합니다. 다음 챕터에서는 이 cycles와 아이폰 프로그램의 주요 디자인 패턴에 대해 설명합니다.



The Application Life Cycle

어플리케이션 life cycle은 시작과 종료 사이에 발생시키는 이벤트의 부분으로 구성됩니다. 어플리케이션이 시작 될 때 아이폰 어플리케이션도 main 함수로부터 시작되는데 이때 UIKit은 어클리케이션의 UI를 로드하고 이벤트를 받을 준비를 합니다. 프로그램이 동작하는 동안 UIKit은 이벤트를 사용자의 오브젝트에 전달하고 명령에 응답하는 역할을 수행합니다. 사용자가 프로그램을 종료시킬 때, UIKit은 어플리케이션에 종료 메시지를 전달하고, 프로세스의 종료를 시작하는 역할까지 수행하게 됩니다. 그림 1은 이러한 어플리케이션 라이프사이클을 도표화 한 것 입니다. 그림 1에서 보면 UIKit에서는 처음에 사용자의 탭으로 어플리케이션이 수행됩니다. 그때 appliationDidFinishLaunching를 통해 어플리케이션을 제어할 수 있습니다. 그 후 main()함수가 실행되고 UIApplicationMain 함수를 통해 이벤트를 받고 어플리케이션으로 전달하며, 어플리케이션은 Handle event를 통해 어플리케이션을 제어합니다. 어플리케이션이 정상적으로 동작하다가 사용자나 시스템이 어플리케이션 종료를 시도하면 applicationWillTerminate 메시지가 발생합니다. 사용자는 이 메시지를 받아서 종료시 처리해야 할 것을 수행 할 수 있습니다. 그 후 어플리케이션이 종료되는 것이 모든 아이폰 어플리케이션의 life cycle입니다.

사용자 삽입 이미지

그림 1. 어플리케이션 라이프 사이클


The Main Function

아아폰 어플리케이션에서 main 함수는 오직 굉장히 작은 일만을 수행합니다. 물론 아주 특별한 예외때 main 함수를 수정하여 사용할 수 있지만, 대부분의 어플리케이션의 main 함수는 코드 1과 같습니다.

#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;
}

main 함수는 오직 세가지의 역할만을 수행합니다. 첫번째로 autorealese pool을 생성하고, UIApplicationMain함수를 호출합니다. 마지막으로 autorelease pool을 릴리즈하고 프로그램을 종료하게 됩니다.

Autorelease는 별도의 글을 통해 자세히 소개하기로 하고, 우선 UIApplicationMain 함수를 살펴보겠습니다. UIApplicationMain 함수는 네개의 인자(Parameters)를 받습니다.첫번째 두번째 인자인 argc, argv는 main 함수로 받는 것으로 쉘에서 프로그램을 실행 할 때 프로그램 실행 명령어와 함께 인자로 들어오는 값을 넣습니다. 그리고 세번째로 주요 클래스의 ID와, 네번째로 어플리케이션의 delegate 클래스를 넣습니다. 여기서 delegate 란 다른 클래스에 어플리케이션의 동작을 위임하기 위해 작성된 디자인 패턴으로, 프로토콜 규칙에 따라 구조를 맞추고, 필요한 메소드를 구현하면 그 클래스가 알아서 동작하게 되는 디자인 패턴을 말합니다. UIApplicationMain의 세번째 네번째 인자에  nil 을 넣으면 UIKit 은 UIApplication 클래스를 기본으로 사용하여, 네번째 인자에 nil을 넣으면 UIKit은 어플리케이션 delegate 가 nib 파일을 통해 로딩 될 것이라고 가정합니다.

The Application Delegate

사용자 레벨(High level)에서의 행동을 모니터링 하는 것은 개발자가 제공하는 delegate 오브젝트의 역할입니다. Delegation(위임) 방식은 UIKit 을 subclassing 하는 복잡함을 방지하는 매우 좋은 디자인 패턴입니다.


The Main Nib File

어플리케이션이 로딩될 때 수행하는 또다른 일 중 하나는 어플리케이션의 nib 파일을 로딩하는 것 입니다. 만약 어플리케이션의 Info.plist 파일이 NSMainNibFile key를 가지고 있다면 UIApplication은 nib 파일이 정의하는 것을 로드 합니다. main nib 파일은 자동으로 로드되는 한 하나의 nib 파일 입니다. 그러나 필요할 때 nib 파일을 사용자가 집접 로드할 수는 있습니다. Nib 파일은 디스크에 저장되는 하나 이상의 오브젝트의 스냅샷이 저장되어 있는 리소스(resource) 파일입니다. Main nib 파일은 일반적으로 window 오브젝트와 delegate 오브젝트가 포함되어 있습니다. 그리고 하나 이상의 윈도우를 제어 하기 위한 key 오브젝트로 구성되어 있습니다. nib 파일을 로딩하면 실제 메모리에 이 오브젝트를 재 구성하여 사용 가능한 상태로 만듭니다. 이것은 UIApplicatonMain에서 로딩하는 것과 동작 상 다른 점이 없습니다.


The Event-Handling Cycle

UIApplicationMain 함수가 초기화 된 후에, 어플리케이션의 이벤트 관리와 그림 그리기를 시작합니다. 이것은 그림 2에 묘사되어 있습니다.

사용자 삽입 이미지

그림 2. 이벤트와 그리기 주기

그림 2는 보면, 운영체제(Operating system)은 사용자의 터치를 감지하여 Event queue에 넣고, Event queu는 어플리케이션에 이벤트를 전달합니다. 어플리케이션 내부에서는 이벤트를 사용해야 하는 오브젝트에 이를 전달합니다. 동작이 완료되면 다시 운영체제로 결과를 돌려주고, 운영체제는 이를 화면에 표현합니다.
아이폰 어플리케이션에서는 멀티 터치 이벤트를 지원합니다. 하지만 멀티 터치가 여러개의 이벤트를 생성하는 것이 아닌, UIEvent라는 하나의 이벤트에 캡슐화 되어 들어가 있습니다. 터치에 관련된 이벤트는 UIEvent에 UITouch 오브젝트를  포함하여 전달하게 됩니다.

어플리케이션이 실행되면, 시스템은 어플리케이션을 위해 프로세스와 하나의 쓰레드를 생성합니다. 생성된 쓰레드는 어플리케이션의 메인 쓰레드가 되고, 이것은 UIApplicaton이 mian run loop 에서 동작합니다. 그림 3은 main run loop 와 이벤트 제어의 관계를 나타냅니다.

사용자 삽입 이미지

그림 3. Main run loop

UIApplication 오브젝트는 입력되는 터치 이벤트를 적당한 responder 오브젝트로 분기하여 mian run loop를 설정합니다. responder 오브젝트는 UIResponder 를 상속받아 만들어지며, UIApplication, UIWindow, UIView, 그리고 모든 UIView의 서브 클래스의 인스턴스를 포함합니다.

추가로, UIResponder 클래스는 responder chain 을 가지고 있습니다. 이것은 만들어지는 이벤트가 링크로 연결되어 전달되며, 첫번째 responder가 이벤트를 처리하지 못하면, 두번째 responder 에 전달되고, 이렇게 끝까지 전달되면서 처리하는 구조입니다.

Fundamental Design Patterns

디자인 패턴에 대한 부분은 별도의 팁 & 태크에서 소개해 드리도록 하겠습니다.


The Application Runtime Environment

Fase Launch, Short Use

아이폰은 동시에 하나의 어플리케이션만 실행할 수 있습니다. 이것은 어플리케이션을 실행하기 위해서는 항상 홈 스크린에서 어플리케이션 아이콘을 클릭하여 실행해야 한다는 것을 의미합니다. 아이폰 어플리케이션은 빠르게 실행되고 빠르게 종료되어야 합니다. 만약 5초 이내로 어플리케이션이 종료되지 않으면 시스템이 이것을 강제로 종료합니다.

아이폰 어플리케이션은 백그라운드에서 동작하지 않기 때문에, 종료시 최종 데이터를 저장해야 다시 실행 했을 때 마지막으로 동작하던 모습을 재현해 낼 수 있습니다.


The Application Sandbox

아이폰 어플리케이션은 보안상의 이유로 파일시스템의 지정된 곳에만 위치할수 있다. 이것은 sandbox라는 보안 기능의 부분 기능입니다. sandbox 라는것은 보안 분야에서 사용되는 언어로, 모든 실행과 데이터를 시스템이 알 수 있는 범위에서 동작하도록 하고 어플리케이션의 모든 행위를 모니터링 할 수 있게 하는 개념입니다. 이것을 위해 아이폰 어플리케이션은 다음의 위치에서만 실행 될 수 있습니다.

/ApplicationRoot/Application ID/


하지만 아무리 sandbox로 동작한다고 해도 어필리케이션의 오버플로우나 기타 해킹 방법으로부터 자유로울 수는 없다는 것을 명심 하시기 바랍니다.


The Virtual Memory System

어플리케이션 메모리를 관리하기 위해 아이폰 OS는 Mac OS와 같은 virtual memory 시스템을 사용합니다. 다만 아이폰에서는 메모리가 부족할 때 디스크에 메모리 페이지를 쓰는 swap 기능을 사용하지 않습니다. 이는 빠른 동작을 위한 조치라고 판단됩니다. 대신 아이폰 OS는 현재 메모리에서 사용하지 않는 메모리의 코드 영역 같은 부분을 내려서 공간을 확보하며, 그래도 메모리가 부족하면 동작하고 있는 어플리케이션에 현재 필요없는 메모리를 해지하라는 메시지를 보냅니다. 어플리케이션은 이 메시지에 응답하여 cache나 불필요한 메모리를 해지할 의무가 있습니다.


The Automatic Sleep Timer

아이폰 OS에서는 베터리를 절약하기 위한 방법으로 자동 sleep timer 를 사용합니다. 사용자가 일정 시간동안 아이폰을 터치하지 않아서 이벤트가 발생되지 않는다면 아이폰 OS에서는 자동으로 시스템을 정지시키고 스크린을 끕니다. 하지만 게임이나 동영상 플레이어 같은 어플리케이션은 사용자 입력 없이도 오랜 시간 동작해야 할 수 있기 때문에 UIApplication 오브젝트의 idleTimerDisabled 속성을 YES로 만들어서 자동 slee timer를 끌 수 있습니다.


The Application Bundle

아이폰 어플리케이션을 빌드할 때, XCode는 Bundle과 함께 패키지 합니다. Bundle은 하나의 그룹화 되어 있는 하나의 디렉토리 입니다. 번들은 아래 내용과 같이 어플리케이션 아이콘, 프로그램 실행 파일 등 여러가지로 구성됩니다.

   MyApp - 실행 파일.Settings.bundle - 프로그램의 속성과 다른 리소스 파일에 대한 내용을 포함

Icon.png - 57 x 57 사이즈의 홈 스크린에서 보여지는 어플리케이션 아이콘

Icon-Settings.png - 29 x 29 사이즈의 어플리케이션이 동작할 때 어플리케이션 이름 옆에 나오는 아이콘

MainWindow.nib - 어플리케이션의 main nib 파일입니다. 이것은 어플리케이션의 main 윈도우 오브젝트와 delegate object 를 포함하고 있습니다. 다른 interface 오브젝트는 추가적인 nib 파일로 부터 로드하거나 소스 레벨에서 포함합니다. Info.plist 파일의 NSMainNibFile key 를 변경하여 이 파일 이름을 변경할 수 있습니다.

Default.png - 480 x 320 사이즈의 이미지로, 어플리케이션이 시작할 때 보이는 이미지 압니다.

iTunesArtwork - 512 x 512 사이즈의 이미지로, 어플리케이션을 배포할 때 보여지는 이미지 입니다. 이것은 appstore에 배포될 때 보여지게 됩니다.

Info.plist - 어플리케이션의 bundle ID, 버전 그리고 보여지는 어플리케이션 이름 등 어플리케이션의 주요 속성이 들어있습니다.

sun.png - 해당 언어가 지원되지 않을 때 보여지는 이미지입니다.

en.lproj, fr.lproj, es.lproj ... - 지원 언어 리소스 입니다.


The Information Property List

Info.plist 파일은 모든 아이폰 어플리케이션이 포함하고 있는 속성 파일입니다. 이것은 XCode의 Active Target TargetName 메뉴를 클릭하여 GUI로 수정할 수 있습니다.(그림 4)

사용자 삽입 이미지

그림 4. Active Target

여기서는 기본적인 이름등을 수정할 수 있고, 더 자세한 설정은 하단에 있는 Open Info.plist as File을 클릭하면 그림 5와 같은 화면이 실행되고 여기서 모든 속성을 수정할 수 있습니다.

사용자 삽입 이미지

그림 5. Info.plist 파일

Handling Critical Application Tasks

이 장에서는 어플리케이션이 꼭 수행해야 할 역할을 기술합니다.


Initialization and Termination

어플리케이션이 초기화되고 종료되는 동안 UIApplication 클래스는 해당 메시지를 전송합니다. 어플리케이션은 delegation 오브젝트에서 이것을 처리해야 합니다. 초기화와 종료를 처리하는것은 필수 사항은 아니지만, 어플리케이션의 초기화때 데이터를 초기화 하거나 종료할 때 데이터를 저장하는 등의 역할을 수행하기 때문에 대부분의 어플리케이션에서는 이 메시지를 이용해야 할 것입니다. 아이폰 어플리케이션은 시작과 종료가 빠르고 가볍게 처리되야 하기 때문에 이 메시지를 적절히 이용해야 하는데, 만약 어플리케이션이 네트워크로부터 데이터를 받아오거나 복잡한 연산을 하여 초기화가 느릴 때, 먼저 UI를 보여주고 그 후에 초기화를 처리하는 방법 등으로 작업을 해야 합니다.

다음 글 박스에서는 UIApplicationDelegate에서 초기화와 종료시에 사용하는 메소드 프로토콜을 설명합니다.

applicationDidFinishLaunching - 어플리케이션이 시작 될 때 실행되는 메소드 입니다.

applicationWillTerminate - 데이터를 저장하거나 어플리케이션의 상태를 저장합니다. 어플리케이션 종료 시 호출됩니다.


Responding to Interruptions

사용자가 홈 버튼을 클릭하여 프로그램을 종료시키는 것 이외에도, 시스템이 어플리케이션에 interrupt를 걸어서 사용자의 입력을 기다릴 수 있습니다. 예를 들어 전화가 오거나 SMS가 오는 경우에 사용자에게 다음 수행을 물어보고 전화를 받는다면 어플리케이션은 종료되게 됩니다. 그림 6은 이러한 동작을 표현합니다.

사용자 삽입 이미지

6. Interrption

1. 시스템이 전화나 SMS가 전송되거나 달력에서 이벤트가 발생하는 것을 탐지합니다.

2. Deligate의 applicationWillResignAcive를 호출합니다.

3. 시스템이 alert 패널을 띄워서 사용자에게 전화나 SMS 수신 등의, 해당 이벤트를 알립니다.

4. 만약 사용자가 해당 이벤트를 무시하면 applicationDidBecomeActive 를 호출합니다.

5. 사용자가 해당 이벤트의 수행을 지시하면 applicationWillTerminate 를 호출합니다. 이때 어플리케이션은 종료시와 마찬가지로 데이터나 어플리케이션 속성을 저장해야 할 것입니다.

아이폰 OS가 sleep 모드로 들어가거나 다시 깨어날 때도 applicationWillResignAcive와  applicationDidBecomeActive가 호출됩니다.


Observing Low-Memory Warnings

시스템이 low-memory notification을 어플리케이션에 전달하면 어플리케이션은 빠르게 필요없는 메모리를 해지해야 합니다. 이 notification을 알 수 있는 방법은 3가지가 있습니다.

  • applicationDidReceiveMeoryWarning 을 delegate에 구현합니다.
  • UIViewController의 didReceiveMeoryWarning 을 override 합니다.
  • UIApplicationDidReceiveMemoryWarningNotification 메시지를 등록하여 처리합니다.
Customizing Your Application's Behavior

이 장에서는 사용자의 경험에 기반하여 어플리케이션을 최적화 하는 방법을 제시합니다.


Launching in Landscape Mode

아이폰 어플리케이션은 기본적으로 potrait mode(세로)로 동작한다. 만약 portrait mode와 landscape mode 둘다 지원한다면 portrait mode 로 시작하는 것이 좋다. 만약 landscape 모드로만 동작하게 하려면 다음의 과정을 거쳐야 한다.

  • Info.plist 파일에 UIInterfaceOrientation 키를 추가하고, 여기에 landscape mode 를 세팅한다UIInterfaceOrientationLandscapeLeft(홈 버튼이 왼쪽 기준)또는 UIInterfaceOrientationLandscapeRight (홈 버튼이 오른쪽 기준) 속성 중 하나로 선택하면 된다.
  • 어플리케이션 UI를 landscape 모드에 맞게 만든다.
  • shouldAutorotateToInterfaceOrientation 을 landscape 모드에서는 YES를 리턴하게 하고, POTRAIT 모드에서는 NO를 리턴하게 한다.

Communicating with Other Applications


만약 어플리케이션이 시스템에 등록된 종류의 URL을 호출하면 시스템은 해당 URL에 해당하는 어플리케이션을 동작시킨다. 예를 들어 Map을 보여주는 URL을 실행하면 등록된 Google map 이 실행되는 것이다. 이것을 통해 어플리케이션간 통신을 수행 할 수 있습니다. 애플에서는 http(사파리), mailto(애플 기본 메일 클라이언트), tel, sms의 URL 기능을 기본적으로 제공합니다. 이 기능을 사용하기 위해서는 NSURL 오브젝트를 생성하여 UIApplication 오브젝트의 openURL 메소드를 사용하면 됩니다. 이를 통해 다른 어플리케이션이 실행되면 기존의 어플리케이션이 잠시 종료되고, 새롭게 실행된 어플리케이션이 종료되면 다시 자동으로 실행되게 됩니다.

다음은 다른 어플레이케이션에 데이터를 전송하는 예제 코드입니다.


NSURL *myURL = [NSURL
URLWithString:@"todolist://www.acme.com?Quarterly%20Report#200806231300"];
[[UIApplication sharedApplication] openURL:myURL];


위 코드를 보면 todolist 로 시작하는 URL을 사용하는 것을 볼 수 있는데, 이것은 아이폰 OS에 등록된 어플리케이션이 실행되면서 뒤의 URL을 전달하게 되는 것 입니다.


Implementing Custom URL Schemes


애플에서 기본적으로 세팅한 URL type은 변경할 수 없지만, 그 외의 URL type은 개발자가 별도로 등록할 수 있다. 이것을 수행하기 위해서는 Info.plist 파일에 CFBundleURLTypes 속성을 통해 등록합니다. 다음 글 박스는 이 속성의 값을 설명합니다.

CFBundleURLName - URL Type의 이름입니다. 이것은 어플리케이션별로 unique 해야 하기 때문에 DNS 를 거꾸로 표현한것 과 같은 com.acme.myscheme과 같은 방식을 사용하기를 권장합니다.

CFBundleURLSchemes - URL의 앞부분에 들어가는 이름을 문자열로 입력하며, 여러개를 사용할 수 있습니다. 예를 들어 todolist, dolist 등과 같이 등록하면 이 형식의 URL이 로드되면 해당 어플리케이션이 동작합니다.


이 기능을 테스트 하기 위해서는 safari를 사용하면 됩니다.


Handling URL Requests


다른 어플리케이션이 URL request를 통해 해당 어플리케이션을 동작시켰다면 이것은 delegate의  APPLICATION:handleOpenURL 메소드를 구현하여 처리할 수 있습니다. 이 메소드를 통해 입력되는 NSURL을 처리하여 동작시키면 됩니다.


Displaying Application Preferences


사용자가 바꾸는 설정이 바로 적용되거나 무엇인가 동작이 바뀌기를 기대하는 것은 어플리케이션 내부에 넣고, 그렇지 않은 것은 시스템의 설정에 넣으면 됩니다. 시스템에 넣는것은 Settings.bundle에 포함시켜서 설정할 수 있으며 Icon-Settings.png를 Bundle에 넣으면 시스템 설정창에 해당 아이콘이 보여지게 되며, 제공하지 않으면 기본적으로 어플리케이션 아이콘이 등록됩니다.


Internationalizing Your Application


텍스트, 이미지 등 모든 리소스는 사용하는 아이폰의 언어에 따라 다르게 보여지게 할 수 있습니다. 시스템에서 기본적으로 제공되는 alert나 기타 컨트롤들은 기본적으로 이 기능을 가지고 있습니다. 일반 어플리케이션에서 이 기능을 사용하려면 pInfo.list 에서 설정하여 사용할 수 있습니다. pInfo.list에서 lproj 폴더를 지정하여 해당 폴더에 코드가 생성하는 텍스트, 기본 텍스트, 아이콘, 사운드 파일, Nib 파일등을 넣을 수 있습니다.

lproj의 서브 디렉토리는 다음과 같습니다.

en.lproj/
- InfoPlist.strings / - 이 디렉토리에는 각 국가별 언어 디렉토리를 하위 디렉토리로 가지고 있습니다. 예를 들어 프랑스 언어는 fr.lproj 디렉토리를 통해 지원할 수 있습니다.
- Localizable.strings / - 어플리케이션이 생성하는 스트링이 포함됩니다.
- sign.png / - 국가별로 구분되는 이미지


NSLocalizedString 매크로를 이용하여 코드상에서 언어를 구분하여 지원할 수 있습니다.


NSString *NSLocalizedString(NSString *key, NSString *comment);

label.text = NSLocalizedString(@"City", @"Label for City text field");


NSLocalizedString은 key와 comment로 구성되어 있습니다. key는 언어를 말하며, 이것을 번역하기 위해 필요한 커맨드를 넣을 수 있습니다. 그 후 lproj 폴더에 다음과 같은 키를 Localizable.strings 파일에 넣으면 해당 언어로 번역됩니다.

"City" = "Ville";

다국어 지원에 대한 것은 더 자세히 팁 & 태크에서 소개해 드리겠습니다.

Tuning for Performance and Responsiveness


Using Memory Efficiently


메모리를 효과적으로 사용하기 위해서는 다음과 같은 사항을 지키시기를 권장합니다.
  • 메모리 릭을 최소화 해라
  • 리소스 파일을 최대한 작게 사용해라
  • 큰 데이터는 SQLite 를 이용하여 저장하고 불러와라.
  • 리소스는 필요할때만 불러와라.
  • Thumb 를 이용하여 컴파일하면 35%의 메모리가 절감된다. 하지만 그만큼 퍼포먼스는 떨어진다.

Allocating Memory Wisely

메모리를 할당할 때는 다음과 같은 사항을 지키시기를 권장합니다.
  • Autorelease 사용을 최대한 줄이고, 개발자가 직접 allocating 하고 release 해라.
  • 리소스를 줄여라.
  • 문제가 되는 메모리 사용을 회피해라.


Reducing Power Consumption


다음 기능의 사용의 최소화 하여야 베터리를 오래 쓸 수 있습니다.
  • Wi-fi radio
  • baseband cell radios
  • Core location framework (GPS)
  • Accelerometers (가속도 센서)
  • Disk
이로서 첫번째 챕터의 소개가 끝났습니다. 지금은 문서를 번역하고, 그에 따른 약간의 양념을 가미한 수준입니다. 하지만 앞으로 팁&태크나 새로운 강좌들을 통해 더욱 많은 소개 드리도록 하겠습니다. 아직까지 애플에서 제공되는 문서를 통해 포스팅을 하는 것은, 원문과 다르게 더 좋은 글을 쓰려고 하는것은 거의 불가능 하므로, 원문에 충실하게 계속 포스팅 하겠습니다.
Posted by Getroot

Leave your greetings.

  1. 정말 최고의 강좌네요. 원리를 알고 아이폰을 접근할 수 있어서 감사합니다. ^^

    2010/03/22 15:55 [ Permalink : Modify/Delete : Reply ]
  2. bellMT.

    좋은정보네요!~ 감사드립니다.

    2010/08/04 11:33 [ Permalink : Modify/Delete : Reply ]
  3. thanks for your posting

    2010/10/01 16:42 [ Permalink : Modify/Delete : Reply ]
  4. pkseop

    멋집니다. 정리하느라 수고 많이 하셨을듯 하네요.

    2010/12/06 20:13 [ Permalink : Modify/Delete : Reply ]