얻을수 있는 장점들:
  1. SQLite로 고속 동작을 보증하는 추상화 모델 클래스를 제공 받을 수 있다. (모델 파일을 더블 클릭하여 새 윈도우에서 엔티티 디자이너를 연상태에서만 새 파일 마법사에 "Managed Object" 항목으로 나온다 - 버그인지 의도인지 모르겠다, 개발자가 부분적으로 오버라이딩 한 경우 머지는 안된다.)
  2. 코어 데이터로 추상화된 모델은 모델이 버전업 했을 경우 매핑 모델을 정의함으로써 데이터 버전업 기능을 쉽게 구현할 수 있다.
  3. 코어 데이터로 추상화된 모델은 WIFI, Bluetooth등으로 싱크할 때 더 편리한 API지원을 받을 수 있다.
  4. 데이터 정합성을 어느정도 보장 받을 수 있다. (관계형 DB에서 삭제 액션 등등)
  5. 이미 존재하는 클래스로 부터도 모델 엔티티 다이어그램을 얻을 수 있다. (하지만 역반영은 불가능하다)
이제부터는 깐다. :)

효율적인 디자인 - 모델 매핑 부재:
맥에서의 개발과는 달리 아이폰, 아이패드에서는 이 코어 데이터와 UI 가 모델 패스로 바인딩 되지는 않는다. 그러나 XIB파일을 일반 xml에디터로 열어 실험해 본 결과, 모델 바인딩이 된다고는 한다. 키밸류 코딩을 이용하면 코드로는 바인딩이 가능한 것이 확실하다. 그러나 이 부분에 대해 애플이 공식적인 지원이 보증될 지는 알 수 없고, 리젝션 위험도 있다.

학습 비용에 대한 리스크:
코어 데이터는 모델로서의 기능 보다 DB Row로서의 특징이 훨씬 강하기 때문에, SQLite 에 대한 이해를 필요로 하며, 동시에 키밸류 코딩 및 옵저빙을 세션 매니저로 활용하므로 Object-C에 대한 깊은 조예를 필요로한다. 따라서 다분야의 전문지식을 갖춘 MDA경험자가 필요하며, 이는 단순하게 교육되거나 커리큘럼에 의해 학습되기 어렵다. 이미 MDA에 익숙한 고급 엔지니어가 아이폰과 같은 초급 기술을 다시 습득하기위해 시간을 투자하는 것은 비용낭비로 비춰지기 쉽기 때문에, 정치적 요건 마련이 필요하다. 또한 이것은 시니어 엔지니어의 작업부담을 높여, 효율적인 분업을 어렵게 할 것이다.

모델 유연성 리스크:
EMF나 기타 모델 제네레이션 프레임웍과 달리, XCode의 모델 클래스 생성기능은 매우 초보적인 수준이어서, 새 파일 만들기만 가능하다. 따라서, 모델 생성 후 후처리 작업에 대한 프로세스를 수동으로 관리해야 하며, 인건비 상승요인이 된다. 또한 모델의 동작 방식은 키밸류 매커니즘에 의해 관리되기 때문에, 단순히 유도속성 하나를 추가하는데에도 최고 수준의 엔지니어가 필요하며, 모델이 리팩토링 될 때마다 투입되어야 한다.

임시 결론:
엔터프라이즈 B2B 에서 엔티티 디자이너는 절실히 필요하지만, SQLite같은 낮은 스케일과 연결된 엔티티를 사용할 수는 없을 것이다. 물론, ManagedObject는 너무 단순하기 때문에 다른 스토어링 코디네이터나, 컨텍스트를 직접개발하는 것이 어려울 것으로 보이지는 않는다. 코어 도큐먼트는 오랜동안 맥의 앱들에서 신뢰성이 확보되었고, 엑스코드 및 아이폰 SDK의 흐름을 보면, 애플이 점점 더 코어 도큐먼트의 지원을 확장하고 있으므로, 여유자금이 충분하다면, 이에 기반한 작업 프로세스를 갖춰 놓는 것도 좋을 것 같다. 

그러나 아이폰 앱의 수익구조를 살펴볼 때, 이러한 다분야 전문가를 몇명이나 고용할 수 있을지는 의문이다. 이러한 고민은 자바 진영 쪽엔 밤하늘에 육안으로 관찰 가능한 별의 수만큼이나 많은 논의와 발전이 있어왔기 때문에, 안드로이드에서 MDA를 도입하는 것은 너무나 쉬운 일이다. 때문에 B2B프로젝트에서 아이폰 개발이 생산성 측면에서 불리할 것 같다. 또한 B2B환경에 작용하는 삼성과 같은 기업의 압력 및 협력 체계 또한 무시할 수 없다.

그럼에도 B2C프로젝트에서 블루투스, 아이튠즈, 와이파이등을 이용한 사용자 데이터 싱크 기능은 사랑받을 것이 분명하고, 코어 도큐먼트를 사용하면 그러한 기능에 대해 빠르게 대처할 수 있다. 하지만 아직까지는 사용자의 데이터를 매우 중요시하여, 그것을 다루는 것이 중점이 된 비즈니스 앱은 많지 않고, 현재 수익이 높은 앱들은 대부분 그러한 특성을 갖고 있지도 않기 때문에, 코어 도큐먼트의 도입은 비용증가에만 머물 우려도 있다. 이러한 특성은 사용자의 눈에 한 두번만에 들어오는 것이 아니기 때문에 가치를 입증받기도 쉽지 않다. 충분한 능력이 있다면 도입할만한 가치나 근거는 분명히 있다. 여러모로 생산성이 뛰어나 질 것이며, 향후 작성할 앱들의 기본적인 품질을 높혀줄 것이다.


'Objective-C' 카테고리의 다른 글

멀티 태스킹 지원시 주의점  (0) 2010.07.23
X-Code의 인터페이스 빌더  (0) 2010.04.28
메모리 관리  (0) 2010.04.25
Getter Method  (0) 2010.04.25
Posted by 지이이이율
,
XCode 3.2.3에서 컴파일된 앱은 iOS 4.0에서 별다른 조치를 하지 않아도, 기본적인 멀티 태스킹 능력을 갖게되는 데 몇 가지 주의 할 점이 있다. 개인적으로 멀티 태스킹이란 용어를 사용하는 것이 조금 망설여진다. 기술적으로 그것은 전혀 멀티 태스킹이 아니기 때문이다. 

일반적으로 멀티 태스킹이란 시분할 시스템을 지칭하는 용어로, CPU를 짧은 시간 단위로 나누어 여러 프로그램에게 차례대로 반복 할당함으로써, 마치 여러 프로그램이 동시에 수행되는 듯한 착각을 일으키는 기술이다. CPU는 충분히 빠르고, 대부분의 프로그램은 연속적으로 CPU를 필요로하지 않기 때문에 매우 효율적이기도 하다.

아이폰4의 멀티 태스킹은 이와는 좀 다르다. iOS 4.0은 홈 버튼을 눌러 앱을 빠져나와도, 해당 프로그램의 메모리를 소거하지 않고, 일종의 집행 유예상태로 남겨둔다. 메모리는 소거하지 않지만, 그렇다고 CPU를 스케쥴해주는 것도 아니므로, 실질적으로 앱은 전혀 실행되지 않는 상태이다. 즉 앱의 종료상태와 백그라운드 상태가 딱히 구분되지 않는다. 일단 종료버튼이 눌리면 유예상태가 되고, 언제 소거될지는 알 수 없다. 다른 앱등에 의해 메모리가 부족한 경우, 가장 과거의 앱 부터 메모리에서 소거되는 것 같다.(이 소거 규칙은 확실하지 않다, 애플은 이러한 내용을 전혀 공개하지 않았다) 기본 메모리가 부족한 3G는 멀티태스킹을 아예 지원하지 않으며, 3GS의 경우엔 게임 한 번정도 실행하면, 이전 태스크는 모두 잃어버린다.

이러한 동작원리는 앱은 자신이 종료되는 시점에, 어떤 형태로 나중에 다시 실행될지 예측할 수 없게 만든다. 다시 실행될 때 메모리에 앱이 남아있다면, 깨우기가 진행되고, 아니면 다시 실행된다. 이런 이유로 만약  앱이 시간복잡도, 외부 자원과 연관을 갖는 경우, 앱은 매우 불안정하게 동작하게 될 수 밖에 없다.

개발자는 이러한 상황을 잘 고려해야 하며, 앱의 특징별로 몇 가지 유형을 정리해 보았다.

첫째. 가장 단순한 유형으로, 응용프로그램이 갖는 컨텐츠가 시간 및 외부 네트워크와 연관되지 않은 경우로, 이 경우엔 대체로 문제가 발생하지 않는다. 대게의 유틸리티성 앱, 악기등과 같이 모든 기능이 앱 내부에 있는 앱들이 이 유형에 속한다. 단 이경우에도 내부 상태를 적절한 시점에 보존해 두지 않으면, 앱이 메모리에서 소거된 뒤 다시 실행될 때, 이전 작업을 모두 잃어버리게 된다.

두번 째로 시간과 연관된 콘텐츠가 있다고 하더라도, 앱 내에서 고유의 시간진행 모델을 갖는 경우 역시, 앱이 백그라운드로 들어가는 순간 시간이 멈췄다가 다시 가게 되므로 그다지 문제 될 것이 없다. 타이밍 기반의 게임(거의 대부분 아케이드, 퍼즐 게임)등이 이에 속한다. 이들 역시 종료되는 시점에는 깨어날 수 있을지 알 방법이 없으므로, 중요한 정보는 즉시 보존해둬야 한다.

세번째로 실제 시간과 연관을 가지는 앱의 경우, 앱이 다시 깨어났을 때, 그동안 흐른 시간에 대해 델타 처리를 해야 한다. 만약 이를 처리하는 시간이 충분히 짧거나 간단하지 않다면, 다시 시작하는 것만 못한 결과가 나타날 수도 있다. 예를 들어 Coin Dozer는 iOS4.0을 지원하면서 백그라운드 태스킹에 들어갔다가 다시 깨어난 경우, 자신이 종료(완전 소거)되었다가 다시 실행된 것인지, 백그라운드에서 돌아온 것인지를 제대로 인지하지 못해, 시간 경과 보상을 주지 않는 경우가 종종있으며, 메모리에서 소거된 경우 진행상태를 완전히 잃어버린다. 이는 근본적으로 아이폰 앱이 엄밀히 말해 *종료*상태와 *백그라운드* 상태가 딱히 구분되지 않기 때문이다.

넷째. 네트워크 자원을 사용하는 경우, 해당 자원은 시간이 흐른 뒤 이미 무효상태를 갖게 되었을 수 있으며, 이것은 매우 골치아픈 문제가 될 수도 있다. 따라서 깨어날 때마다, 정보 유효성 검사를 해야 하는데, 외부 자원을 억세스하고 검증하는데는 많은 시간이 걸린다. 예를 들어 로그인이 필요한 서비스의 경우, 앱이 백그라운드에서 깨어났을 때, 이미 서버쪽에서 그 세션은 만료되어 파기 되었을 수 있다. 사용자는 작성중이던 블로그나 코멘트를 덧 없이 잃어버릴 수 있으며, 개발자는 자기자신이 가진 서버에 대한 클라이언트가 아닌 경우 이런 상황을 디버깅하기가 매우 힘들다. 트위터, 메신저등과 같이 정보가 *추가*되기만 하는 경우는 별로 문제가 되지 않지만, 동적으로 정보가 편집되거나, 삭제될 수 있는 자원인 경우에, 멀티태스킹은 지원하지 않는 편이 나을 수도 있다. 이 경우 컴파일만해도 기본적인 멀티태스킹이 자동으로 되게 되어버리므로, 주의해야 한다.

다섯. 외부 자원 및 실제 시간이 컨텐츠와 연관을 갖는 경우에는 매우 심각한 다양한 문제가 발생할 수 있다. 위룰, 갓 핑거등과 같은 실시간 SNS게임이 이에 속한다. 만약 서비스 클라이언트가 한대가 아닌경우 문제는 더욱 심각해질 수 있다. 기본적으로 SNS, MMORPG, 이 메일, 캘린더 등과 같은 애플케이션은 그 서비스에 영향을 미칠 수 있는 경로가 매우 방대하다. 웹, 또는 다른 유저등이 그 원인이 된다. 예를 들어, 아이폰에서 이메일을 읽는 도중, 백그라운드로 전환하고 PC나 맥에서 그 메일을 지워 버리면, 간단하게 데이터 해저드가 성립된다. 별로 복잡하지 않은 간단한 시나리오 테스트만으로도 아이폰 빌트인 앱 조차 제대로 대응하지 못하고 죽어나갔다.

결론.

iOS 4.0은 누군가의 말 마따나, 애플의 비스타가 될 가능성도 농후하다. 배터리, 성능, 경험 세마리 토끼를 다 잡는다는 전략은 매우 우아하고 칭찬 해 줄 만한 일이지만, 일반 사용자에게 이것의 동작방식은 매우 이상해 보일게 분명하다. 백그라운드에서 실제 동작하지 않는데, 동작한다고 착각함으로써 생기는 부분이라던지, 왜 어떤 경우에는 같은 방법으로 종료했는데도, 다시 안 깨워지는지등에 대한 부분은 전문 개발자가 아니고서는 쉽사리 이해하기 힘든 부분이다. 개인적으로 이 모든 나쁜 경험은 단지 개발자의 탓으로 매도될 것이 거의 분명하다고 생각하기 때문에, 조금 분통이 나기도 한다. 애플이 성공한 것은 아이폰이 훌륭해서가 아니라 SDK 공개(사실은 그 이전부터)로 수많은 개발자가 *참여*한 덕분이라는 사실을 잊어서는 안 될 것이다.

'Objective-C' 카테고리의 다른 글

아이폰 앱 개발시 코어 데이터 도입 타당성  (0) 2010.08.02
X-Code의 인터페이스 빌더  (0) 2010.04.28
메모리 관리  (0) 2010.04.25
Getter Method  (0) 2010.04.25
Posted by 지이이이율
,
빠르게 UI 및 어플리케이션을 공급하려는 시도는 늘 있었다. 마크업으로 UI를 정의하고 컨트롤러를 연결하고 하는 식의 아이디어는 늘상 새롭다고 재잘대고 잘난 척 하지만 늘 한계가 있었던 게 사실. 결국 독자적인 UI 상속체계를 확립하지 않고는 사용자의 요구사항을 달성할 방법이 없었다.

- 프로그래머 세계에는 리유즈 가능한 UI라는 전설이 있어.
- 어떤 전설인가요?
- 난 전설 따윈 믿지 않아.

XCode의 인터페이스 빌더는 매우 흥미롭다. 이름만 들으면 그저 폼 에디터 정도일 것 같지만, 컨트롤러나 모델의 인스턴스도 위지윅으로 생성이 된다. 델리게이트라고 부르는 묵시적 콜백 설정 또한 역시 드래그 앤 드랍으로 선을 그어 완성된다. 단언컨데 리스너를 부착하는 작업 같은게 위지윅으로 되는건 살다 살다 처음 봤다. 거기에 각종 뷰의 모델을 바인딩 하는 것 역시 드래그 앤 드롭으로 가능하다. 코코아가 제공하는 기본 데이터 구조에 대한 컨트롤러는 대부분 구현되어 있다. 

뭥미, 컨트롤러를 위지윅으로 작성하는게 어딨어!? 요깄네. 와, 이건 뻥이 아니다. UI코드를 쓰거나, 상속할 필요가 실제로 없다. 이부분이 중요하다. IT영업자의 발언이 아닌 엔지니어의 발언이다.

비록 Object-C의 문법의 변태성향이나 말랑말랑한 묵시적 특징들이 날 짜증나게 하긴 하지만 이것 하나 만큼은 정말 다른 개발 환경과는 다른 수 많은 아이디어가 재미있게 녹아있고, 또 사랑하지 않을 수 없을 것 같다.

'Objective-C' 카테고리의 다른 글

아이폰 앱 개발시 코어 데이터 도입 타당성  (0) 2010.08.02
멀티 태스킹 지원시 주의점  (0) 2010.07.23
메모리 관리  (0) 2010.04.25
Getter Method  (0) 2010.04.25
Posted by 지이이이율
,

메모리 관리

Objective-C 2010. 4. 25. 21:27
95년 부터 자바를 주 언어로 채택해 사용하기 시작하면서 메모리 관리에 대해 다시 고민할 일은 없으리라 생각했었는데, Objective-C때문에, 이 케케묵은 주제와 다시 마주해야 했다.

코코아 개발 그룹에서는 가비지 컬렉터를 품위 없는 것으로 생각하는 것 같으며, 퍼포먼스에 문제를 제기하고 있다. 특히 동영상 편집, 녹음등과 같은 저작도구를 킬러타이틀로 많이 가진 맥이란 점에서, 예측할 수 없는 타이밍에 걸리는 로드는 치명적이라는 것이다. 거기에 더하여 10.5 이전의 OS는 가비지 컬렉터가 아예 안 될 뿐만 아니라, 아이폰, 아이팟에서도 사용할 수 없기 때문에, 사실상 제품이 아닌 모듈 제작 입장에서는 무조건 개발자가 손수 쓰레기를 주워야 한다. (모듈을 사용하는 개발자가 GC를 쓸지 안 쓸지 알 수가 없기 때문에 그들에게 민폐를 끼치지 않으려면...)

혁신적인 아이디어를 떠올리고, 디자인하고, 구체화하기도 바빠 죽겠는데, 근 15년 만에 쓰레기까지 직접 손으로 주워야 한다니, 이 얼마나 품위 없는 짓거리인지 짜증이 확 몰아치지만, 아무튼 대세 플랫폼이니 그들의 전통을 연구해 보자.


참조수

맞다 그 참조수다. 

최첨단의 아이폰에서, 가장 오래된 메모리 관리기법에 대해 이야기하는 것이 좀 우아하지 못하긴 하지만, 어쨌든 일반적으로 C++에서 레퍼런스 카운터라고 부르는 그 참조수에 관한 이야기이다. NSObject 는 다음과 같은 두 함수를 가지고 있다.

(void) retain;
(void) release;

retain 메시지를 보내면 참조수가 1증가 한다. release 메시지를 받으면 참조수가 1 감소하며 참조수가 0이 되면 메모리에서 *자동* 으로 해제 된단다. 정확히는 dealloc 이 호출된다. (이런 정도가 자동으로 여겨지던 시절이 있긴 했다.)

객체가 생성되면 최초 1의 참조수를 갖게 된다. 

Person* p = [Person alloc];
이 수행되는 순간 p는 참조수가 1이된다.

[p release];
이제 참조수가 0이되어 메모리에서 제거된다.

상식적인 이야기이긴 하지만, 릴리즈는 콤포지트 패턴의 형태로 릴리즈된다. - 자신이 dealloc 될 때 자신의 구성 요소들을 모두 릴리즈 시킨다. - 물론 당신이 만들 클래스도 그래야 한다. 배열등과 같은 객체는 이미 그런 컴포지트 릴리즈가 구현되어 있다.


AutoRelease

코코아 책에서 오토 릴리스라는 단어를 봤을 때, 그러면 그렇지 이렇게 노역꾼 같은 일까지 개발자가 직접할 리는 없겠지, 그래 내게 우아한 자동 릴리즈를 알려줘 라고 생각했으며, 그 결과 깊은 상처를 입어야 했다.

오토 릴리스란, 메인 이벤트 루프에 도달한 후에 릴리즈되도록 예약하는 것을 말한다. UI 이벤트 루프에 비동기적으로 코드를 연결해 실행하는 것을 생각하면 될 것 같다.

이것은 특정 함수가 결과 객체를 리턴하면서 더 이상 그 객체에 대해 관심을 갖지 않는 경우(즉 리테인 할 필요가 없는경우)를 위해 생겨난 도구이다. 함수는 그 객체에 관심은 없지만 그렇다고 리턴하기 전에 릴리스하면 참조수가 0이 되어 객체가 사라져버리는 낭패가 생길 수 있다. 이 경우, 메소드를 호출한 쪽에서는 원하는 결과를 받아 볼 수 없을 것이다. 그렇다고 그냥 리턴해 버리면 불필요한 참조수가 1 증가된 상태로 결과가 전달되었으므로 좀비 객체가 될 것이다.

이럴 때 

[result autorelease]; // 여기서 그냥 release 를 했다간 객체가 증발해 버리는 낭패가 생길 수 있다.
return result;

위와 같이 하면, 스택이 메인 루프로 돌아갔을 때 예약된 autorelease 가 수행되어 참조수가 줄어들게 된다. 어떤 메소드들은 위의 예처럼 autorelease 된 객체를 리턴하는데, 이것은 순전히 개발자 마음이기 때문에 받은 결과를 내가 릴리즈해야하는지 여부는 일일히 잘 확인하는 수 밖에 없다. 아멘.


Setter와 Retain

통상적으로 한 객체가 setter함수를 통해 어떤 객체를 전달 받으면, 그 객체를 참조하고, retain 한다.
-(void) setFoo: (Foo*) newFoo{
  [newFoo retain]; 
  [foo release];
  foo = newFoo;
}

retain을 먼저하는 것은 중요한 사안이다. 만약 newFoo와 foo가 같은 객체에 대한 포인터였다면, 릴리즈를 먼저하는 순간 객체를 잃어버리게 될 것이기 때문이다. Objective-C는 C++의 확장이기 때문에 제품의 기능과는 무관한 이런 상황들을 개발자가 세밀하게 고려해야만 한다.

또 foo를 릴리스할 때 이것이 nil이었다고 하더라도 Objective-C에서는 아무 에러도 없이 그냥 지나가게 된다. 함수가 동적으로 매핑되기 때문에 null로 전달 되는 메시지는 자동적으로 무시된다. 그야 가장 보편적인 실수의 형태에 대해 시스템이 죽는 것을 방지하기 위한 조치로 생각 되지만, 디버깅을 개발자의 무덤으로 만드는 정책으로 여겨지는 것 또한 사실이다.

'Objective-C' 카테고리의 다른 글

아이폰 앱 개발시 코어 데이터 도입 타당성  (0) 2010.08.02
멀티 태스킹 지원시 주의점  (0) 2010.07.23
X-Code의 인터페이스 빌더  (0) 2010.04.28
Getter Method  (0) 2010.04.25
Posted by 지이이이율
,

Getter Method

Objective-C 2010. 4. 25. 20:45
Objective-C 에서는 자바에서 보통 빈즈를 디자인 할 때 사용하는 getter/setter 형태의 메소드 네이밍, 그중에서도 getXXXX 형태를 사용하지 말 것을 권고하는데, 그 이유는 전통적 코코아 개발자들이 get으로 시작하는 메서드의 경우 결과를 return 값으로 전달하는 것이 아니라 레퍼런스를 통해 값을 메모리에 기재해 주는 것이 관행이기 때문이란다. Objective-C 에서는 이러한 경우 그냥 XXXX를 쓴다고 한다.

자바:
Data getData();

Objective-C 관행:
- (void) getData[Data*];
- (Data*) data;

이러한 전통은 C시절 부터 있던 것이어서 30년전의 케케묵은 규칙을 다시 따르자니 조금 진절머리가 난다.

'Objective-C' 카테고리의 다른 글

아이폰 앱 개발시 코어 데이터 도입 타당성  (0) 2010.08.02
멀티 태스킹 지원시 주의점  (0) 2010.07.23
X-Code의 인터페이스 빌더  (0) 2010.04.28
메모리 관리  (0) 2010.04.25
Posted by 지이이이율
,