본문 바로가기

콘텐츠/클라우드

앱스토어 애플리케이션 따라하기 #1

아이폰이 한국 시장에 출시된 지 2개월 이상 됐다. 그동안 기존 휴대폰 사용자들의 상당수가 아이폰을 선택, 30만 대 이상이 판매됐다고 한다. 또한 애플의 앱스토어에서 판매되는 애플리케이션의 개수도 기하급수적으로 늘어나 3억 5,000개 이상이라고 한다. 최근 앱스토어에 올라오는 애플리케이션을 보면 양적인 성장과 함께 질적으로도 초기 판매되던 것들 대비 매우 훌륭하다.

안경훈 linuxgood@gmail.com|리눅스와 맥OS에 관심이 많으며, 모바일 디바이스에서 동작되는 사용자 중심의 프로그램을 개발하는 것에 흥미를 갖고 있다. 현재는 삼성SDS에서 근무 중이다.

앱스토어에 올라오는 애플리케이션들의 구현 원리를 생각해 보고, 실제로 구현하는 연습을 해 보자. 지면이 허락되는 대로 다음과 같은 대표적인 기능의 구현 방법을 알아볼 것이다.

1. View의 전환
2. 지도 애플리케이션

View의 전환
많은 아이폰 애플리케이션에서 기본적으로 View의 전환이 사용된다. 거의 모든 애플리케이션에서 형태의 차이는 있지만 View간의 전환이 사용된다고 보면 된다. 이번 호에서는 IB를 이용해 몇 개의 뷰를 만들고, 그 뷰를 MainView에 올린 후 버튼을 이용해 전환하는 예제를 알아보자. 


<화면 1> View 전환의 예



1 새로운 프로젝트를 생성한다. ‘File | New Project...’ View-based Application 템플릿을 선택한다.


<화면 2> 새로운 프로젝트 생성

2  viewChangeTest라는 디렉토리와 프로젝트를 생성한다.    <화면 3>과 같이 4개의 파일이 생성될 것이다.


<화면 3> viewChangeTest 디렉토리 및 프로젝트 생성

3 viewChangeTestAppDelegate.h, viewChangeTest AppDelegate.m 소스에서 생성된 viewChangeTestView Controller를 네비게이션 바를 활용해 View와 View를 서로 전환할 것이므로 navigationController로 변경한다. 이 작업을 하기 전에 Resources 디렉토리의 MainView.xib를 더블클릭함으로써 IB에서 먼저 navigationController를 추가하자.
최초의 MainView.xib는 <화면 4>와 같이 생겼다.


<화면 4> 최초의 MainView.xib

4 여기서 ‘viewChangeTestViewController’는 사용하지 않을 것이므로 <화면 5>와 같이 삭제한다(삭제하지 않고 navigationbar를 올려도 되지만 일단 깔끔하게 삭제!). 그럼 ViewController가 없는 상태가 된다.


<화면 5> viewChangeTestViewController 삭제

5 이제 IB의 Library창에서 navigationController를 Inspector 창으로 드래그해서 가져온다. 이 동작은 Navi gationController에 필요한 리소스를 첨가하는 과정이다. 


<화면 6> navigationControlooer를 Inspector로 드래그

6 이제 Xcode 에디터 창으로 돌아가서 viewChangeTest AppDelegate.h에 <리스트 1>과 같은 코드를 추가한다. @property를 추가하는 것은 setter, getter 접두어를 생략하기 위한 목적이다.

<리스트 1> 화면 전환을 위한 View 만들기

#import <UIKit/UIKit.h>

@class viewChangeTestViewController;

@interface viewChangeTestAppDelegate : NSObject <UIApplicationDelegate> {
   UIWindow *window;
   UINavigationController *navigationController;
}

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

@end

나중에 혼동이 없도록 MainView로 사용할 때 viewChange TestViewController를 UINavigationContller로 변경했다.

다음으로 viewChangeTestAppDelegate.m도 viewController로 돼 있는 부분을 navigationController로 <화면 7>과 같이 변경한다.


<화면 7> viewChangeTestAppDelegate.m 변경

7 이제 inspector 창을 보면서 설정이 잘 돼 있는지 점검한다. <화면 8>은 inspector 창에서 차례대로 설정한 화면이다.


<화면 8> Inspector 설정 화면

8 이제 navigation bar의 title을 변경하자. ‘View와 View의 이동 예제’라고 이름 붙였다.

9 이제 중요한 Main View를 설정할 차례이다. View를 클릭하고, View Controller 속성(Attribute)에서 <화면 10>처럼 NIB Name의 viewChangeTestViewController 항목을 선택한다. 그러면 Loaded From viewChangeTestViewController라는 이름으로 변경된다. 이렇게 되는 이유를 곰곰이 생각해 보자.


<화면 9> View와 View의 이동 예제


<화면 10> NIB Name의 viewChangeTestViewControlle 선택

10 이제 viewChangeTestViewController.xib를 더블클릭해서 navigation bar를 배치하고, 버튼처럼 사용할 Table View 를 만들어 보자. 처음에는 <화면 11>과 같은 식으로 돼 있으니 기존의 UIView는 지워준다(수정해도 되지만 깔끔하게...).


<화면 11> UIView 삭제

11 Table View object를 inspector 창으로 드래그 한다. 이번 호에서는 다른 View로 전환하기 위한 버튼의 역할을 Table View가 할 것이다.


<화면 12> Table View object를 inspector 창으로 드래그

12 속성 창에서 <화면 13>과 같이 Style과 Status Bar, Top Bar를 수정해 준다. 여기서 Top Bar를 Navigation Bar로 만들어 주는 것을 꼭 기억해야 한다. Table View는 <화면 13>의 오른쪽처럼 보이게 된다. Table View에 기본적으로 들어가 있는 데이터를 빌드하면 나오지 않으니 현재 보이는 모양에 신경 쓰지 않아도 된다.


<화면 13> 속성창 변경

이제 메인 화면의 모든 UI가 완성됐다.

다음으로 inspector 창에서 <화면 14>와 같이 Outlets을 연결해 주고, Referencing Outlets 항목에서 dataSource와 delegate를 Table View로 수정한다.


<화면 14> Outlets 연결 및 dataSource와 delegate 수정

13 viewChangeTestViewController가 UITableView Controller를 상속받도록 header의 내용을 <리스트 2>와 같이 변경해 준다. viewChangeTestView Conroller.h 파일에서 고치면 된다.

<리스트 2> header 변경

#import <UIKit/UIKit.h>

@interface viewChangeTestViewController : UITableViewController {
}

@end

14 우리는 View간의 이동을 실습할 것이므로 이동할 새로운 View를 하나 만든다. View에 포함된 내용은 무엇이든 상관없다. <화면 15>와 같은 순서로 만들어 봤다. 


<화면 15> 새로운 View 생성

Resources ->오른쪽 클릭 -> Add -> New File...

UIViewController subclass로 만든다. Options을 보면 UITableViewController subclss에 체크가 돼 있는데, 분위기를 보고 눈치 챈 이들도 있을 것이다. 이것은 여기서 또 subclass View를 만들 경우에 체크하면 유용하게 아래로 계속 View를 만들 수 있도록 코드 템플릿을 제공하겠다는 의미이다. 이 예제에서는 굳이 체크하지 않아도 상관없다. 필자는 체크하지 않았다.


<화면 16> UIViewControler subclass 생성

NewView01.m이라는 이름으로 만들었다. NewView01.h와 IB를 위한 NewView01.xib 파일이 생긴다.


<화면 17> NewView01.m으로 이름 설정

15 이제 NewView01 뷰를 불러오기 위해 MutableArray Class를 사용한다. <리스트 3>과 같이 viewChange TestViewController.h 파일에 써준다.

<리스트 3> MutableArray Class 사용

#import <UIKit/UIKit.h>

@interface viewChangeTestViewController : UITableViewController {
   NSMutableArray *subArray; //subArray로 NewView01을 불러올 것이다.
}

@end

16 viewChangeTestViewController.m 파일에 Table Array를 구성한다. 다음과 같이 이전에 만들어 둔 header 파일을 먼저 import해야 한다.

#import “NewView01.h”
...

awakeFromNib 함수에 View에 대한 초기화와 NewView01을 호출하는 부분을 추가한다. 이 함수는 IB에서 만든 xib가 불린 후에 호출된다. 따라서 viewChangeTestView Controller.xib가 호출될 때 <리스트 4>의 함수가 호출되는 것이다. 여기서는 최초로 보여지는 화면에서 버튼으로 사용될 Table의 첫 번째 array에 대해 정의한다. array의 맨 처음 항목을 버튼으로 사용하는 예이다.

<리스트 4> MutableArray를 활용한 View 호출

// xib가 불린 후에 호출됨.
- (void)awakeFromNib {
   if (subArray==nil) {
      subArray = [[NSMutableArray alloc] init];

      // 그룹을 추가할 것이다.
      [subArray addObject:[[NSMutableArray alloc] init]];// MainView
      [subArray addObject:[[NSMutableArray alloc] init]];// NewView01
   }

   // NewView01 호출
   NewView01 *pTestView = [[NewView01 alloc] initWithNibName:@"NewView01" bundle:nil];
   [[subArray objectAtIndex:1] addObject:
   [NSDictionary dictionaryWithObjectsAndKeys:
   @"iPhone Objects 예제", @"title",@"viewController",
   pTestView,@"viewController",
   nil]];
   [pTestView release];
}

만약 메인 화면의 버튼을 2개로 만들고 싶다면 다음과 같이 따라하면 된다.

- NewView02라는 이름으로 Add File을 추가한다.
- awakeFromNib 함수에 아래의 코드를 추가한다.

[subArray addObject:[[NSMutableArray alloc] init]];  // for NewView02

- 다음으로는 NewView02를 호출하는 코드를 작성한다.

// NewView02 호출
NewView02 *pTestView2 = [[NewView02 alloc] initWithNibName: @“NewView02” bundle:nil];
[[subArray objectAtIndex:1] addObject:
[NSDictionary dictionaryWithObjectsAndKeys:
@“iPhone Objects 예제2”, @“title”,@“viewController”,
pTestView2,@“viewController”,
nil]];
...
[pTestView2 release];

최종 결과물은 <화면 18>과 같다.


<화면 18> 최종 결과물

앞에서 봤던 코드 이외에도 Table View와 관련된 나머지 코드가 <리스트 5>와 같이 존재한다.

<리스트 5> Table View와 관련된 코드

(void)viewWillAppear:(BOOL)animated {
   [super viewWillAppear:animated];
}

(void)viewDidAppear:(BOOL)animated {
   [super viewDidAppear:animated];
}

(void)viewWillDisappear:(BOOL)animated {super viewWillDisappear:animated];
}

(void)viewDidDisappear:(BOOL)animated {super viewDidDisappear:animated];
}
....


- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [subArray count];
}

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

(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  
   static NSString *CellIdentifier = @"Cell"
  
   UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

   if (cell == nil) {
       cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
   }
  
   // Configure the cell.
   int section = indexPath.section
   int row = indexPath.rowtextLabel.text = [[[subArray objectAtIndex:section] objectAtIndex:row] objectForKey:@"title"];

   return cell;
}
// select table
(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
   UIViewController *targetViewController = [ [[subArray objectAtIndex: indexPath.section] objectAtIndex:indexPath.row ] objectForKey: @"viewController"];self navigationController] pushViewController:targetViewController animated:YES];
}

(void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
   [super didReceiveMemoryWarning];

// Release any cached data, images, etc that aren't in use.
}

(void)viewDidUnload {
   // Release any retained subviews of the main view.
   // e.g. self.myOutlet = nil;
}

(void)dealloc {
   [super dealloc];
}

이제 Table View의 항목을 클릭하면 View가 전환되고, 전환된 View에서는 타이틀 바의 back 버튼으로 이전 View로 돌아가는 애플리케이션이 작성됐다.

지도 애플리케이션
지도 서비스는 GPS가 내장된 아이폰을 사용하는 사람들이 가장 많이 사용하는 서비스 중의 하나일 것이다. 국내의 지도 서비스는 대형 포털이나(다음, 네이버) 구글 등에서 제공하는 OpenAPI를 가져와서 많이 제작된다. 각각의 지도 OpenAPI는 미세한 차이는 있으나 사용법에 있어서는 비슷한 결과를 보여준다.

이번 호와 다음 호에서는 아이폰 SDK 최신 버전(3.1.3)에 포함된 지도 Object인 MapKit을 기반으로 하는 지도 서비스 애플리케이션의 작성 방법을 알아보자.

애플리케이션 아이콘 등록

아이폰에서 애플리케이션의 여러 가지 속성을 결정하는 것 중의 하나가 *.plist 파일이다. 이는 아이폰용 애플리케이션을 위한 여러 가지 설정 정보를 담고 있는 XML 파일이다. 실행 전에 사용되는 information-property list와 실행 시에 설정된 내용을 사용하는 엔티티 설정 등이 있다(push Notification이나 사용자 keychain 같은 보안 설정).plist 파일은 Xcode workspace의 ‘Groups & Files | Resources’ 항목에서 선택할 수 있다.


<화면 19> plist 파일 선택

아이폰에서 보여지는 아이콘 파일을 등록하는 하기 위해서는 plist 파일에서 Icon file 항목에 추가하면 된다. icon을 등록하기 위해서는 먼저 프로젝트에 해당 아이콘 파일을 등록해야 한다. 파일 타입은 png 형식으로 한다. <화면 20>의 왼쪽 아이콘은 ‘Icon file’이 등록되지 않았을 경우이고, 오른쪽 아이콘은 png 형태의 아이콘을 등록했을 경우이다.


<화면 20> 아이콘 등록

아이폰 SDK에 포함된 MapKit 활용
아이폰 OS 3.0 이상에서는 <화면 21>과 같이 화면을 구성할 때 구글 맵 API들을 사용해 손쉬운 방법으로 지도 관련 API들을 이용할 수 있게 됐다. 구글의 구글 어스 API 사용법과 용어에 대해서는 http://code.google.com/apis/maps/iphone/terms.html을 참조하자.

MapKit framework에는 다음과 같은 맵 관련 API 헤더들이 있다.

MKAnnotation.h MKAnnotationView.h MKMapView.h MKPinAnnotationView.h
MKPlacemark.h MKReverseGeocoder.h MKTypes.h MKUserLocation.h


<화면 21> 구글 OpenAPI 함수를 활용한 MapView의 예

그리고 <표 1>의 클래스를 활용하게 된다.

이렇게 MapKit에 어떤 종류의 클래스가 존재하는지 알아봤다. 다음 호에서는 정의된 여러 가지 클래스를 활용해 실제로 지도 애플리케이션을 구현하는 방법을 배워보자.

 

 

 

 

 

 



이달의 디스켓 : viewChangeTest.zip

참고자료
1. MKMapViewDelegate Protocol Reference.
2. MapKit_Framework_Reference.pdf