QuickDic(참고: http://semix2.tistory.com/489)을 개발하고 나서 아이폰 앱 개발에 흥미를 더해 새로운 앱을 계획한 결과로 ProMan(참고: http://semix2.tistory.com/492)을 만들었다. ProMan은 이슈트레커인 Trac을 벤치마킹한 프로젝트 관리 도구로 프로젝트 뿐만 아니라 일정/스케줄 관리에도 활용할 수 있는 일종의 플래너다.







마지막 업데이트가 2010년 11월이라니!


업데이트 계획도 있었고, 실제 작업도 진행 중이었으나 일의 진전이 크게 없었고, 그렇게 하루 이틀 밀리던 차에 레니타 디스플레이가 나타나고, 또 그렇게 세월아 네월아 하는 사이에 아이폰 5가 등장했다. 그 사이 나는 TEDiSUB과 yaPlayer, MatrixCAM을 개발했다.


작년 한해는 yaPlayer에 H.264 가속 기능을 넣으려고 발악하고 있었다. 나도 저 기능을 꼭 구현하고 싶은데- 하는 욕심으로 머릿속이 가득 차 다른 일이 손에 잘 안잡히더라; 뭐, 핑계겠지. 게을러서 그랬습니다. 가장 솔직한 대답이다.


얼마 전 아이폰 5 스크린 사이즈에 대응하지 않는 앱을 앱스토어에서 강제로 내릴 거라는 기사를 읽었다. 당장 업데이트가 힘들 것 같았기에 스스로 앱을 내렸는데 곰곰히 생각해보니 안되겠더라. ProMan은 내게 특별한 의미가 있기 때문이다.




ProMan이 내게 특별한 이유


ProMan은 내 생의 첫 유료 앱이다. 판매량은 무척이나 미미했지만, 그래도 당시에는 3일에 한 카피 꼴로 판매가 이루어졌다. 미국에서 한 카피, 네덜란드에서 한 카피... 생각치도 못했던 나라에서 한 카피 팔릴 때마다 그 느낌이 참 이상했다. 내가 만든 무언가에 내가 모르는 누군가가 돈을 지불하는구나! 앱스토어 대단한데? 내가 과연 다른 방법으로 세계인을 대상으로 장사라는걸 할 수 있을까??


고교 시절 꿈 중에 하나는 중국에서 젓가락을 파는 거였다. 중국 국민 전체가 젓가락을 하나씩만 사 준다면 나는 떼부자가 되겠지- 하지만 중국어도 할 줄 모르고, 길거리에서 팔다가 공안에게 잡힐 수도 있고, 중국으로 나가는 것도 문제고, 젓가락은 또 어떻게 만들지? 그냥 마트에서 사면 비싸니 직접 만들어야하는데 그러려면 공장을 알아봐야하나? 공장을 직접 운영해야 하나?


하지만 앱스토어는 이런 고민을 한 방에 날려버렸다. 필요한건 앱을 개발할 맥 한 대, 그리고 책상에 앉아 코딩할 노동력이면 충분했다. 개발한 결과물을 앱스토어에 등록만 하면 전세계 매장에 자동으로 진열되고, 결제 같은 복잡한 문제는 그 쪽에서 알아서! 아- 세상 진짜 좋아졌구나!! 그 당시의 기쁨으로 나는 이런 글도 썼다. 


참고: 청년들이어, 앱스토어에 도전하라! 




헬게이트를 열다!


작년 한 해 머릿속을 가득 채웠던 H.264 가속 기능을 마침내 구현하고 (관련된 이야기는 다음 포스트에 다룰 예정) 곧장 ProMan 소스 코드를 열었다. 몇 년만에 다시 열린 코드는 컴파일 조차 바로 되지 않더라.


사실 컴파일이 안되는 문제는 별 것 아니었다. 컴파일러가 버전업되면서 조금 더 깐깐해졌지 때문이었고, 깐깐해진만큼 똑똑해져서 어떻게 고치면 되는지 알려주기까지 하더라. 뭐, 좋다. 그럼 이제 어디를 고쳐야 하는지 분석해보자.


  • 레티나 디스플레이 지원: ProMan은 이미지를 별로 쓰지 않기 때문에 고해상도 이미지를 추가하는건 그리 큰 일이 아니다. 하지만 ProMan에서 항목을 생성할 때 사진을 첨부할 수 있는데 이 때 첨부사진을 조작하는 과정에서 레티나 디스플레이를 고려하지 않아 저해상도로만 저장되는 문제가 있었다.
  • 아이폰 5 스크린 사이즈 대응: 최근 개발한 TEDiSUB, yaPlayer, MatrixCAM과 달리 ProMan은 개발 당시 스크린 사이즈가 바뀔거라는 생각을 못했기 때문에 절대좌표로 때려넣은 요소가 한 둘이 아니었다. 처음부터 고려했더라면 아이폰 5 사이즈에 대응하는건 일도 아닐텐데, 이번만큼은 상황이 최악이었다. 
  • 항목 편집기에서 편집 항목 전환이 제대로 동작하지 않는 문제: iOS가 업데이트되면서 내부 동작에 미묘한 변화가 있었다. 특히 이번에 문제가 된건 애니메이션 코드. ProMan을 개발할 당시 딱딱 맞게 동작하던 애니메이션이 최신의 iOS에서는 애니메이션이 중첩되면서 제대로 동작하지 않더라.
  • 첨부사진의 저장 방식: 첨부 사진을 PNG 포맷으로 했는데 대체 내가 왜 그랬을까 싶다; 필요 이상으로 용량을 너무 크게 잡아먹거든. 게다가 무슨 깡이었는지 첨부사진을 통째로 데이터베이스에 넣어버렸다. 대체 내가 왜그랬을까?

이번의 목표는 새로운 기능을 추가하는게 아니다. 새로운 기능을 넣고 싶어도 이번만큼은 안된다. 레티나/아이폰 5 스크린에서 제대로 동작하는, 그리고 최신의 컴파일러 특징에 대응하는 정제된 코드를 만들어야 한다.



하나씩, 하나씩! 

1. ARC 적용
2. @synthesize 코드 제거
3. 불필요한 함수 선언 제거 

코드를 열어 가장 먼저 한 작업은 Objective-C 최신 기술 중 하나인 ARC를 적용하는 것이었다. 얼마 전까지만 해도 나는 ARC에 대한 신뢰를 크게 갖지 못했었는데 TEDiSUB을 업데이트 하면서 ARC를 적용해보니 장점이 많더라. 가장 큰 장점은 코드량이 현저히 줄어든다는 것! 같은 기능을 할 때 코드는 적을 수록 좋다. 그 만큼 유지보수가 쉬워지기 때문이다. 

ARC 적용과 더불어 @synthesize 코드를 제거했다. 예전에는 @property로 선언한 속성에 대해 멤버 변수를 따로 선언해야 했지만 지금은 그럴 필요가 없으므로 불필요한 변수 선언문도 함께 제거했다. 그리고 함수 선언을 최소화 했다. ProMan을 개발할 당시에는 함수가 사전에 선언되어있지 않으면 호출할 수 없었다. 하지만 언제부턴가 이럴 필요가 없어졌다. 함수의 노출은 최소화할 것! 이 역시 유지보수를 쉽게 하는 방법이다.

이 두 가지 작업이 생각보다 오래 걸렸다. 사실 Xcode는 ARC 전환을 자동으로 해 주는 기능을 제공하는데 나는 이 기능을 크게 신뢰하지 않는다. 게다가 하도 오랜만에 코드를 열었더니 이해가 안되는 부분도 많아 코드를 찬찬히 살펴볼 필요도 있었다.


4. 항목 편집기의 전환 문제 해결

편집 항목을 전환하는 애니메이션이 제대로 동작하지 않는 문제는 두 개의 서로 다른 애니메이션 코드가 동시에 따로 실행될 때 발생했다. 후자의 애니메이션이 전자의 애니메이션을 취소시키기 때문이다. 그런데 문제는 아무리 찾아봐도 두 개의 애니메이션이 따로 불리는 부분이 없단 말이지;; 

한참을 고생하다가 결국 문제의 원인을 찾아냈다. 어떤 함수가 다음과 같이 작성되어 있었는데 이 부분에 문제였다.

- (void)setHideWithAnimate:(BOOL)animate {
	NSTimeInterval duration = 0;
	if (animate) {
		duration = 0.2;
	}
	[UIView animate animateWithDuration:duration animations:^{
		...
	}];
} 


이 코드에서 animate가 NO이면 duration이 0이되어 애니메이션 없이 ... 블록이 실행된다. 아니, 그럴거라 생각했다. 하지만 실제로는 duration이 0이어도 ... 블록은 애니메이션으로 처리되어 이전의 애니메이션을 취소시켰다. 문제의 원인을 찾기까지는 오래 걸렸지만 이 코드를 고치는건 금방이다.



5. 아이폰 5 사이즈 대응


은근히 고된 작업이었다. TEDiSUB을 아이폰 5 사이즈에 대응시키던 때와는 차원이 달랐다. 항목 편집기, 항목의 상세 정보 표시 등 주요 요소들이 모두 내부에서 절대좌표를 계산해서 사용하고 있었다. 큰 덩어리 내부를 그리는 코드는 별 문제가 없었지만 항목 편집기처럼 큰 덩어리를 레이아웃하는 코드 내에서 절대좌표를 사용한 것은 치명적이었다.


iOS6의 오토레이아웃을 이용했더라면 상황이 훨씬 쉽게 풀렸을지도 모른다. 하지만 아직 오토레이아웃에 대한 경험이 부족하고, 최소 실행 환경을 iOS5로 잡았기 때문에 오토레이아웃을 사용할 수 없었다. 그런고로 레이아웃 코드를 직접 고쳤다.


이 때 문제가 된 것 중 하나는 UIViewController의 viewDidLoad 함수 내에서 view 크기를 읽을 때 아이폰 4/5 사이즈를 분별할 수 없다는 것이다. 이게 참 의아한데, 아무리 다시 해봐도 그랬다. viewDidLoad 함수 내에서 전체를 구성하는 view의 크기를 읽으면 실제 스크린 사이즈가 아닌 XIB에서 설정한 크기가 반환된다.


이 문제는 아래와 같이 viewDidLoad 함수가 끝난 직후 view 크기를 읽게 해서 해결했다.


- (void)viewDidLoad {
	 [super viewDidLoad];

	dispatch_async(dispatch_get_main_queue(), ^{
		[self resetLayout];
	}
}


UIViewController 내에도 layout 관련 함수가 있고, 이걸 오버라이드하는 방법도 있지만 그 경우 내가 의도한 시점에 레이아웃을 재설정하기가 어렵기 때문에 위와 같은 방법을 사용했다. 조금 이상해 보이기도 하지만 잘 돌아가면 장땡!



6. 레티나 디스플레이 지원


앱 내에서 사용되는 이미지를 모두 레티나에 대응시켰다. 그리고 첨부사진으로부터 썸네일 이미지를 생성하는 코드, 그리고 첨부사진의 최대 폭을 1024로 제한해 리사이즈하는 코드가 레티나를 지원하도록 UIGraphicsBeginImageContext 함수 대신 UIGraphicsBeginImageContextWithOptions 함수를 호출하고 scale 값으로 0을 전달했다. 이렇게 해야만 UIGraphicsGetImageFromCurrentImageContext 함수를 불러 컨텍스트로부터 이미지를 생성할 때 레티나 디스플레이 특성이 반영된다.



7. 첨부사진의 저장 방식을 PNG에서 JPG로 변경


사진 저장 방식을 JPG로 바꾸는 것 자체는 일도 아니다. 문제는 ProMan에서 첨부사진을 데이터베이스에 직접 넣고 있었다는 것. 그래서 이미 저장된 첨부사진에 대해서도 변경이 이루어져야 한다. 즉 데이터베이스 마이그레이션이 요구된다.


어차피 데이터페이스를 마이그레이션해야 한다면 이 참에 첨부사진을 데이터베이스에 직접 쓰지 않고 외부에 파일로 두게 하는게 좋을 것 같았다. 


CoreData를 이용하고 있었기 때문에 새 버전의 모델을 생성하고, 마이그레이션을 위한 매핑모델을 생성했다. 그리고 첨부사진에 대해서만 커스텀룰을 적용하여 새 버전의 데이터베이스에 사진을 넣는 대신 외부 파일로 저장하고 해당 URL만 데이터베이스에 저장하도록 했다.


이 때 주의할 점 하나! 파일 URL은 항상 전체 경로가 아닌 마지막 부분, 즉 파일명만 기록해야 한다. 왜냐하면 간혹 앱 업데이트, 또는 기기를 복구할 때 앱의 설치 경로가 변경되기 때문이다. 데이터베이스에 저장된 전체경로를 그냥 이용했다간 이런 상황에 대응할 수 없다.




몇 가지 디자인 변경


작업을 마치고 테스트를 하던 도중 몇 가지 디자인 문제를 발견했다. 이 문제를 고치는건 새로운 기능을 추가하는게 아니기 때문에 큰 부담이 없다고 판단해서 이번 업데이트에 포함시켰다.


우선 마일스톤과 티켓이 쉽게 구분되지 않는다는 점을 고치고 싶었다. 각각의 표현 방식이 다르기 때문에 구분은 가능했지만 주의 깊게 관찰하지 않으면 비슷해 보였다. 그래서 마일스톤/티켓을 보여줄 때 상단 네비게이션바의 색상을 다르게 하기로 결정했다. (마일스톤과 티켓의 디자인을 다르게 하는 것도 하나의 방법이지만, 그렇게 하면 앱의 아이덴티티가 사라질 것 같아서 관두었다)


마일스톤이 표시될 때 상단 네비게이션바의 색상을 붉은색으로 했다. 중요한 일임을 강조하고 싶었기 때문이다. 그리고 티켓이 표시될 때는 주황색을 썼다. 갑자기 다른 색이 나타나면 정신 없고 혼란스럽기 때문에 최대한 분위기를 유지하는 상태에서 변경을 주고자 주황색을 선택한 것이다. 극적인 분리 효과는 없었지만 그래도 어느 정도 개선되었다고 본다.


이렇게 해놓고 보니 앱 아이콘이 문제가 되었다. 그동안 ProMan 아이콘은 파란색이었다. 하지만 테마색이 빨강/주황색이 되었기 때문에 앱 아이콘의 색상도 바뀔 필요가 있었다. 전문 그래픽 디자이너는 아니지만 최선을 다해 앱 아이콘을 새로 디자인했다. 테마색을 이용했고, 앱 이름이 잘 표시되도록, 그리고 체크 마크를 이용해 앱의 목적이 일정 관리임을 나타내었다. 


편집/설정 버튼의 디자인이 너무 노후되어 보였다. iOS 플랫폼이 제공하는 기본 버튼을 이용했는데 뭐랄까- 마치 전문 서적의 예제 프로그램 같은 느낌을 풍겼다. 그래서 둥근사각형을 포기하고 최신 유행인 플랫 디자인을 따랐다. (말은 그럴싸하지만 그냥 둥근사각형을 없앤게 전부임; )


코멘트를 편집/삭제하기 위해서는 해당 코멘트를 스와이프(옆으로 밀기)해야 하는데 이 동작을 모르는 사람들을 위해 마지막 코멘트 아래에 안내 문구를 추가했다. 스와이프 동작은 단축키와 비교할 수 있다. 단축키는 알면 간편하게 사용할 수 있지만, 모르면 모르는데로 메뉴에서 직접 해당 기능을 찾아 호출할 수 있어야 한다. 하지만 ProMan에서는 스와이프 동작 이외의 방법으로 코멘트를 조작할 방법을 제공하지 않는다. 편집 버튼은 마일스톤/티켓을 수정할 뿐, 코멘트를 조작하지 않는다. 코멘트만을 위한 별도의 편집 버튼을 추가하기는 어려웠다. 버튼을 추가할 공간이 없었고, 억지로 넣을 경우 두 개의 편집 버튼으로 인해 사용자가 혼란을 느낄 것 같았다. 결국 안내 문구를 추가하는 것이 최선책이었다.


마지막으로 앱을 한글화했다. MatrixCAM 개발 때도 느꼈지만 한글화하고나면 앱이 전혀 다르게 보인다. 신기하다; 




여담


3년만에 꺼낸 코드는 너무나 당황스러웠다. 개발툴의 진전으로 인해 그동안 코드를 간편하게 작성할 수 있는 많은 방법이 생겼는데 3년 전의 코드는 그런 기술 하나 없이 너무나 우직했기 때문이다. 


업데이트를 끝내고나서 적는 글이라 '이렇게 저렇게 고쳤음' 하고 쉽게 이야기하고 있지만, 코드를 연 직후부터 이틀간은 그야말로 멘붕이었다. 이거 괜히 열었나 싶기도 하고, 과연 제대로 고쳐낼 수 있긴 할까 싶은 의문이 자주 들었다. 뭐 그래봤자 코드는 코드일 뿐이고, 내가 만든 거니까. 3년 전의 나를 돌이켜보는 뜻 깊은 시간이었다고 생각한다. 나는 이렇게 변했구나- 가끔 대화형으로 작성한 주석을 읽고선 큭큭 거릴 때도 있었고. 초등학교 때 일기장을 꺼내보는 느낌이랄까? 힘들었지만 지나고보니 재밌는 시간이었다. 업데이트하길 잘했다고 생각한다.




신고

CATEGORIES

티스토리 툴바