최초 작성일 : 2010/09/03 01:47 


우선 먼저 양해 말씀 드릴 것은 제가 이 실전 소스 분석을 진행하는 목적은

애플이 제공하는 API에 대한 자세한 설명이 아니라 이제 시작하는 개발자로서

일종의 시행착오 경험을 공유하고자 하는데 있습니다. 따라서 기본 API에 대한

설명은 과감하게 생략을 하고 넘어갑니다. 이점 양해 부탁드립니다.


==============================================


1. 아이폰에서의 데이터 관리


이번 분석에서는 일반적인 진도상으로는 좀 이른 감이 있지만 소스의 흐름상 먼저 등장을 하고 있으므로

코어 데이터에 대해 다뤄보도록 하겠습니다.


잘 알고들 계시듯이 아이폰에서는 여러가지 방식의 데이터 저장 공간을 사용할 수 있습니다.

SQLite를 직접 사용하는 방법, 바이너리 파일을 사용하는 방법

(여기에는 다시 property list를 사용하는 방법과 객체 archiving을 이용하는 방법 2가지가 있습니다.),

그리고 마지막으로 코어 데이터를 이용하는 방법.


각각의 특징을 보자면 다음과 같습니다.


1.1 SQLite

우선 가장 접근하기 쉬운 것은 SQLite를 직접 사용하는 방법이라고 생각됩니다.

기존에 웹이나 기타 RDBMS 관련 개발을 해보신 분들은 쿼리를 직접 작성하여 entity간의 관계를 지정하고

검색 조건을 위한 where절을 만들고 하면서 익숙하게 데이터 처리를 할 수 있을 것입니다.


1.2 Binary

다음으로 바이너리를 이용한 방법은 기존 언어에서 객체 직렬화라는 부분을 생각하시면 될 것입니다.

객체 직렬화(serialization)란 데이터를 저장하고 있는 클래스의 인스턴스를 그대로 바이너리 파일로

저장하는 기법입니다. JAVA의 예를 들면 HashMap을 상속받은 클래스에 나라 이름을 key로 하고

그 나라 수도를 value로 하여 저장을 한 뒤 이 클래스의 인스턴스를 파일로 저장시키는 방법입니다.


괜히 말이 복잡해졌는데 쉽게 말씀드려 텍스트 에디터로 열었을 때 이상한 문자로 보여지는 파일이

특정 애플리케이션에서는 정상적인 문자로 보여지는 파일들은 모두 이러한 객체 직렬화를 통해

저장되었다고 보시면 됩니다…^^


예를 들어 아래 한글의 hwp 파일은 텍스트 에디터에서는 이상한 문자로 보이지만 아래한글 프로그램에서는

정상적인 문서로 보이는 것이 그런 경우입니다.


1.3 Core Data

마지막으로 애플에서 구현해놓은 Core Data를 이용하는 방법입니다.

사실 제가 이 방식을 선택한 이유는 애플에서 구현해 놓은 것이기 때문에 반드시 익혀놓아야 할

필요성이 있을 것 같아서였는데 익숙하지 않은 구조로 인해 엄청 애먹었습니다…ㅠ.ㅠ

일종의 ORMapping 역할을 하는 API입니다. JAVA로 보자면 iBatis나 Hibernate에 해당하는 건데요.

원칙적으로 따지자면 개발자는 무지 편한 구조입니다. 일일이 쿼리를 작성하지 않아도

(물론 iBatis나 Hibernate에서는 최초 쿼리는 작성을 해 놓아야 합니다. 단지 재사용이 가능할 뿐이죠)

데이터를 관리할 수 있다는 것이죠.


필요한 메서드에 필요한 인자만을 넘겨서 호출하면 Core Data가 다 알아서 쿼리도 날려주고

결과 값도 돌려주고 한다는 것이죠. 하지만 이 캡슐화(객체 지향의 주용 개념 중 하나로 핵심 로직을

인터페이스 뒤로 숨기고 개발자는 외부로 드러난 인터페이스만을 통해 API를 다룰 수 있게 하는 것)는

저처럼 실력이 떨어지는 개발자에게는 무지 헷갈리는겁니다. 자꾸 몰라도 되는 부분이 궁금해져서 진도가

안나가는거죠…-.-


어쨌든 익숙해지면 가장 편한 방법이 되겠지만 세밀한 컨트롤을 원하는 개발자들에게는

다소 답답한 면이 있을 것입니다.


사실 아직도 제가 잘 모르겠는 부분은 Entity간의 relationship을 어떻게 사용하느냐 하는 것입니다.

기존 RDBMS같은 경우 쿼리를 통해 다양한 join을 만들어 데이터를 불러오는데 코어 데이터에서는

어떤 부분이 그런 기능을 하게 되는지 잘 모르겠습니다. 이 부분. 즉, 테이블간의 조인이

코어 데이터에서는 어떤 식으로 이루어지고 또 개발자들은 어떤 작업을 해주어야 하는지에

대해 아시는 분은 부연 설명 부탁드립니다...^^;;;


2. Core Data의 구조


시작이 너무 장황했네요.

암튼 결론적으로 저는 Core Data를 선택했고 생소한 개념과 객체들로 인해 상당히 헤맸고

아직도 헤매는 중입니다…^^;;;


사실 이글을 작성하는 시점에서도 이 부분을 어떻게 풀어나가야 하는 고민에 손을 못대고 있었는데

다행히 한눈에 딱 들어오는 개념도가 보였습니다.


아래 그림은 '위키북스'에서 나온 'More 아이폰 3 프로그래밍'이라는 책에 실린 그림입니다.






책에는 한글로 표시되어 있었는데 오히려 더 헷갈리는 것 같아서 제가 API용어로 다 바꿔봤습니다.

각각의 의미와 역할은 다음과 같습니다.


1. Persistent store : 영구 저장소라고 해석되고 가장 최종 데이터가 저장되는 영역입니다.

                          물리적으로는 하드디스크(메모리)에 저장된 데이터를 가지고 있는

                          바이너리 파일이라고 생각하시면 됩니다.

2. Data Object Model : Persistent store에 저장된 내용들을 논리적으로 보여주는 객체라고 생각하시면 됩니다.

                          xcode상에 보여지는 xcdatamodel 파일을 생각하시면 될 것 같습니다.

3. Persistent store Coordinator : 영구 저장소와 Managed Object Context를 이어주는 다리 역할을 한다고

                          보시면 됩니다. 항상 영구 저장소에서 뭔가 실제적인 것을 가지고 오려고 하면 직접

                          영구 저장소에 접근하는 것이 아니라 이 Persistent store Coordinator를 거쳐야 하는 것입니다.

                          '왜 그렇게 해야 하는가?'라는 질문은 잡스형님께…^^;;;

                          (이런 것도 사실 객체 지향의 일환은로 핵심적인 내용들은 보다 안정적인 위치에 감춰두고

                           개발자들에게는 제한된 인터페이스만을 제공하여 불필요한 변경으로 인한 문제를 줄이는 동시에

                           내부 API가 변경이 되더라도 개발자들은 딱히 수정을 하지 않아도 되도록 하는데 그 목적이 있겠죠.)

4. Managed Object Context : 객체 관리 컨텍스트인데요 개발자의 작업은 여기서부터 시작된다고 보셔도 됩니다.

                          위의 3가지는  최초 애플리케이션이 실행되는 시점에 한 번 코딩을 해주시면 되고 

                          이 Managed Object Context부터는 수시로 사용을 하게 됩니다.

                          물론 인스턴스를 계속 만드는 것은 아니구요.

                          자세한 것은 코딩을 보시면서…^^

5. Entity Description : Entity는 쉽게말해 RDBMS의 테이블을 생각하시면 됩니다. 특정 Entity와 관련된 각종 정보를

                          가져올 수 있는데요 Managed Object Model이나 property(RDBMS의 필드 혹은

                         컬럼이라고 생각하시면 됩니다.)

                          또는 타 Entity와의 관계(relationship) 등의 정보를 가져오거나 설정할 수 있습니다.

6. Managed Object : Managed Object Context에서 관리되는 객체 중 하나입니다.

                          쉽게 말하면 Entity를 클래스 파일로 만들어놓은 것이라고

                          생각하시면 됩니다. 이후 실제 코딩 작업 설명에 자세히 말씀드리겠지만 xcdatamodel 파일을 통해

                          구성된 Entity들은 클래스 파일로 만들 수 있습니다.

                          다만 이 클래스 파일이 항상 필요한 것은 아니고 개발자가 별도의 메서드를 추가시키고자 할 때나

                          사용을 하게 됩니다.

                          전 아무생각없이 다 만들었네요…-.-

7. Fetch Request : 속칭 '쿼리를 날린다'라는 것입니다…^^ 실제 이 과정을 통해 결과값을 받아오게 되죠.

8. Predicate : '술어'라고 해석을 하더군요. where 조건에 해당하는 객체입니다.

                  이런 부분의 사용이 아이폰 개발을 처음 접하는 개발자들을 울리게 되죠…ㅠ.ㅠ


3. 실제 소스 보기


우선 디버깅을 위해 찍은 로그를 좀 보시죠.

최초 실행되는 iPhotoDiaryAppDelegate에서 단순히 실행되는 순서대로 메서드명을 찍은 것입니다.


2010-09-02 22:43:14.742 iPhotoDiary[2610:307] DEBUG: applicationDidFinishLaunching

2010-09-02 22:43:14.753 iPhotoDiary[2610:307] DEBUG: managedObjectContext

2010-09-02 22:43:14.759 iPhotoDiary[2610:307] DEBUG: persistentStoreCoordinator

2010-09-02 22:43:14.764 iPhotoDiary[2610:307] DEBUG: applicationDocumentsDirectory

2010-09-02 22:43:14.778 iPhotoDiary[2610:307] DEBUG: managedObjectModel

2010-09-02 22:43:14.925 iPhotoDiary[2610:307] DEBUG: managedObjectContext

2010-09-02 22:43:14.931 iPhotoDiary[2610:307] DEBUG: managedObjectContext

2010-09-02 22:43:14.936 iPhotoDiary[2610:307] DEBUG: managedObjectContext

2010-09-02 22:43:14.941 iPhotoDiary[2610:307] DEBUG: applicationDocumentsDirectory


이제는 익숙해진 단어들이 보이네요.


다음은 소스입니다.


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

Debug(@"applicationDidFinishLaunching");

// 이 부분에서 앞으로 데이터를 사용할 필요가 있는 컨트롤러들에게 ManagedObjectContext들을 할당해주고 있습니다.

//    처음에는 Core Data의 구조를 몰라서 이러한 순서를 통해 ManagedObjectContext를 가져온 것이 아니라

//    각 화면 컨트롤러에서 별도로 ManagedObjectContext의 인스턴스를 만들어서 사용했더니 계속 Entity를

//    찾을 수 없다는 오류가 뜨더군요.

appMainViewController.managedObjectContext = [self managedObjectContext];

calendarView.managedObjectContext = [self managedObjectContext];

diaryListController.managedObjectContext = [self managedObjectContext];

eventListController.managedObjectContext = [self managedObjectContext];

// 요거는 다음번에 설명을 하겠지만 binary형태의 저장중 property list를 이용한 저장 관련 내용입니다.

[self writeToPlist];


// 다 아시는 내용…^^;;;

[window addSubview:tabBarController.view];

[window makeKeyAndVisible];

}



위 코드는 이 글을 작성하면서 바뀌었습니다. 역시 무식하면 손발이 고생이라고…ㅠ.ㅠ

원래의 코드는 탭바에서 보여질 각 화면 컨트롤러에 managedObjectContext를 넘겨주는 방식인데

사실 코딩을 하면서도 뭔가 이상하다 했습니다…^^;;;


ApplicationDelegate에 접근하는 방법을 몰랐던 거죠.


결국 각각의 화면 컨트롤러의 fetchedResultsController를 호출하는 시점 이전에

       

iPhotoDiaryAppDelegate *appDelegate =

   (iPhotoDiaryAppDelegate *)[[UIApplication sharedApplication] delegate];

self.managedObjectContext = appDelegate.managedObjectContext;


이렇게 코딩하여 변경하였습니다.


호출 순서대로 설명을 해보자면


최초에


appMainViewController.managedObjectContext = [self managedObjectContext];

호출을 하게되면 영구 저장소에 접근하기 위해서 persistentStoreCoordinator를 호출하게 되고

persistentStoreCoordinator는 영구 저장소가 위치한 경로를 알아내기 위해

applicationDocumentsDirectory를 호출하게 되는 것입니다.


이후로 3번 더 managedObjectContext를 호출하였는데 더이상 persistentStoreCoordinator

applicationDocumentsDirectory가 호출되지 않은 이유는 managedObjectContext

persistentStoreCoordinator가 지연 로딩. 즉, 이미 해당 객체가 있으면 기존의 객체를 리턴하고

없으면 새로 생성해서 넘겨주는 것이죠. 그렇기 때문에 최초 managedObjectContext호출 후 객체가

생성되었으므로 이후 3번의 호출에는 managedObjectContext객체를 새로 생성하는 것이 아니라

기존 객체만을 돌려주어 이후 메서드들이 호출되지 않은 것입니다.


나머지 메서드들은 최초 프로젝트 생성시 코어데이터를 사용하겠다는 옵션에 체크를 하셨다면 자동으로 생성되는

메서드들이라 코드는 생략합니다.


프로젝트 생성시 네비게이션 베이스, (아이패드)스플릿 뷰 베이스, 유틸리티 어플리케이션, 윈도우 베이스 등의

프로젝트에는 User Core Data for storage라는 옵션이 나옵니다.






물론 프로젝트 생성시 이 옵션을 체크하지 않았어도 데이터 모델을 만들 수 있습니다.

Groups & Files에서 적절한 위치에 오른쪽 버튼 클릭 후 Add -> New File…을 선택하시면 iPhone OS의 Resource 항목에

Data Model이 있습니다. 물론 이렇게 만들었을 경우에는 아래 4개의 메서드들을 모두 코딩을 해주어야 합니다.


managedObjectContext

persistentStoreCoordinator

managedObjectModel

applicationDocumentsDirectory






4. 정리


우선 최초 말씀드린대로 각각의 API 함수들에 대한 내용은 제 설명보다는 다른 강좌나 애플의 API 문서를 보시는 것이

이해가 빠를 것입니다. 그래서 자세한 설명은 생략을 하였습니다.


다만 중요한 것은 Core Data의 구조와 흐름이 어떻게 되느냐입니다.


Persistent store에 applicationDocumentDirectory로 영구 저장소의 경로를 확인한 Persistent store Coordinator를 통해 접근하여

ManagedObjectContext를 가져오고 개발자들은 ManagedObjectContext를 이용하여 구체적인 작업을 하면 된다.


5. 마무리


아직 초반인데 너무 깊이 들어간 면이 없지 않습니다.

하지만 제가 제목을 [실전 소스 분석]이라 한 만큼 이미 완성된 소스를 따라가면서 전체적인 프로그래밍의 흐름을

되짚어보고자 하는 것이 목적이다보니 이른 시점에 어려운 내용이 등장을 하게 되었네요.


내용이 내용이니만큼 한 회 분량으로는 도입부 정도의 내용밖에는 다루지를 못했습니다.

다음 시간에 나머지 내용들, ManagedObjectContext, FetchResultController, Predicate 등을 다루어 실제

데이터를 읽고, 쓰고, 지우고, 수정하는 부분을 살펴보도록 하겠습니다.


벌써 9월이네요. 환절기에 감기들 조심하시고

다음 시간에 뵙겠습니다.

길고 영양가 없는 글 읽어주셔서 감사합니다.

블로그 이미지

마즈다

이미 마흔을 넘어섰지만 아직도 꿈을 좇고 있습니다. 그래서 그 꿈에 다가가기 위한 단편들을 하나 둘 씩 모아가고 있지요. 이 곳에 그 단편들이 모일 겁니다...^^