Index
1.Controller Does Matter.
2.Choose Which One Do You Use
3.Navigation Controller
4.TabBar Controller
5.Then How About HYBRID?
6.What’s NEXT?


1.컨트롤러는 중요합니다 Controller Does Matter

언제나 모든 일에는 순서가 있습니다. 가장 기초가 되는 것부터 세세한 것까지 가지치기를 하면서 빌드업하고, 심화해나가는 것이 마땅합니다. 이런 프로세스는 개발에서도 마찬가지입니다. 아키텍처를 설계하고, 기본이 되는 대원칙을 설정하고, 이 단계를 지나면 어떤 요구사항에 맞추어 어떤 컴포넌트를 사용할 것인지 고민합니다. 그리고 세부내용 구현을 시작하죠.

01


iOS 개발에서는, 아키텍처 설계를 마치고 바로 다음 단계, 기본이 되는 대원칙을 설정하는 부분에서 고려해야 할 것이 있습니다(물론 이 순서가 절대적인 것은 아닙니다). 그것은 바로 ‘어떤 컨트롤러를 사용해서 화면 전환을 가져갈 것이냐’하는 것입니다.

어떤 컨트롤러를 사용할 것인가 하는 부분은 꽤나 크리티컬한 부분입니다. 애플리케이션 전체의 플로우를 좌우하고, 사용자 경험에 있어서도 큰 차이가 있습니다. 적절한 컨트롤러를 적소에서 사용하지 않은 채로 프로젝트를 빌드하면 시간이 지나고 돌이킬 수 없는 상황이 발생할지도 모릅니다.

02
기초가 중요합니다.


그래서 이번 글에서는, 루키 iOS 개발자들이 간과하기 쉽지만 너무 중요한, Navigation Controller와 TabBar Controller를 간단히 소개하고, 또 어떻게 사용할 것인지 알아보고자 합니다.


2.어떤 컨트롤러를 사용할까요? Which controller do you use?

먼저 개발할 프로젝트가 어떤 형태인지 이해해야 합니다. 물론 기획하는 사람이 따로 있는 회사 프로젝트라면, 기획안에 맞추어 개발하는 것이 맞겠습니다. 그러나 일반적으로, TabBar Controller와 Navigation Controller의 중대한 차이점에 대해 잘 인지하고 있는 기획자는 흔치 않습니다.

03
초록색 잉크로 빨간 선을 그려주세요.


숙련된 iOS 개발자라면 기획안에서 발견한 내용을 어떻게 구현하는 것이 가장 좋은지, 그리고 어떤 대원칙을 가지고 기획안을 구성해야 하는지 피드백을 줄 수 있어야 합니다.

이제 프로젝트의 유형에 따라 하나의 컨트롤러를 선택해봅시다. 우선 프로젝트의 구조가 비교적 간단하고, 화면의 타입이 많지 않으며, 두 번 이상의 depth로 이동하는 일이 잦은 경우라면, Navigation Controller를 추천합니다.

비디오1 - Navigation Controller 트랜지션

반면에, 프로젝트의 화면 구조가 여러 타입의 분류로 구성되어 있고, 두 번 이상의 depth로 이동하는 일이 빈번하지 않은 경우엔TabBar Controller를 사용하길 추천합니다. 실제로 서비스 중인 대부분의 애플리케이션들이 사용하거나, 차용하고 있는 구조의 컨트롤러입니다.

비디오2 - TabBar Controller Tab간 이동




3.Navigation Controller를 사용해봅시다. Let’s use Navigation Controller

Navigation Controller는, 새로운 화면이 Stack으로 계속 쌓이면서 화면을 브라우징하는 개념의 컨트롤러입니다. 루트가 되는 컨트롤러가 가장 밑에 깔리고, 신규 화면은 그 위에 순차적으로 쌓입니다. 이렇게 다음 플로우로 이동하는 작업을 Push라고 합니다.

04
Stack from wikipedia


그러다 보니 Navigation Controller에서 플로우가 길어지면 첫 화면으로 돌아가기 위해 Back 버튼 / Swipe 제스처를 수없이 반복적으로 수행해야 하는 문제가 발생합니다. 이런 경우에는 별도의 버튼을 두어 루트 화면으로 돌아갈 수 있도록 구현해야만 합니다. 이렇게 이전에 디스플레이 되던 화면으로 되돌아 가는 작업을 Pop 이라고 부릅니다.

비디오3 - 무한 back

위에서 언급한 대로, 화면의 구조가 비교적 단순한 경우에는 Navigation Controller가 직관적으로 사용하기에 유용합니다. Navigation Controller는 Xib/Storyboard 에서 찾아서 추가할 수 있습니다.

05
Navigation Controller in Storyboard


Navigation Controller를 사용하기로 마음 먹었다면, 어떻게 다음 화면으로 depth를 태울 수 있는지를 먼저 알아야겠죠. 두 가지 방법으로 이 작업을 수행할 수 있습니다.

첫 번째는, Segue를 이용하는 방법입니다. 국내 개발자들 사이에서는 ‘세그’, ‘시구’ 등으로도 읽히고 있지만, 여기서는 ‘세구에’ 라고 읽겠습니다. 스토리보드에서 Segue를 추가하여 다음 ViewController로의 플로우를 지정할 수 있습니다. 이렇게 하면, 코드로 유연하게 변경하는 것 보다는 조금 불편할 수 있으나 시각적, 직관적으로 플로우를 확인할 수 있다는 장점이 있습니다.

06
Segue in Storyboard


두 번째는, 제가 추천하는 방법입니다. 코드를 통해 다음 플로우를 결정하는 방법입니다. 이 방법은 앞서 소개한 Segue를 사용하는 방법보다는 시각적이지 않지만, 연차가 쌓인 개발자에게는 오히려 익숙하고 편안한 방법입니다. 코드로는 다음과 같이 적용할 수 있습니다.

//MARK: ViewController Utilities
    /**
    NavigationController상의 ViewController를 교체한다
    
    - parameter navigationVC:   ViewController를 보여줄 UINavigationViewController
    - parameter viewController: 화면에 표시할 UIViewController
    - parameter isInDepth:      depth를 태우는 경우 true, 루트 ViewController를 리셋하는 경우 false
    */
    func displayViewController(_ viewController: UIViewController, resetRootView: Bool, animation: Bool) {
        if !resetRootView {
            rootNavigationController?.pushViewController(viewController, animated: animation)
        }
        else {
            rootNavigationController?.viewControllers = [viewController]
        }
    }

코드1 - pushViewControllerAnimated, popViewControllerAnimated




4. TabBar Controller를 사용해봅시다. Let’s use TabBar Controller.

TabBar Controller는, 각각의 Tab에 해당하는 ViewController들과 그 플로우를 따로 관리하는 개념의 컨트롤러입니다. 각각의 Tab에 ViewController를 지정하고, 그 ViewController들이 각각의 State를 스스로 관리합니다. 각각의 탭을 선택하면, 다른 탭의 ViewController에는 영향을 주지 않고 화면을 전환할 수 있게 됩니다.

07
TabBar


반면에 각각의 화면에 하나의 ViewController만이 존재하고, 새로운 화면을 depth 이동하려면 별도의 Navigation Controller를 구현해야 하는 불편함이 있습니다. 이 방법에 대해서는 나중에 말하겠습니다.

TabBar Controller 역시 Xib/Storyboard 에서 찾아서 추가할 수 있습니다.

08
TabBar Controller in Storyboard


TabBar Controller를 사용하기로 했다면, 몇 개의 Tab이 필요한 지 결정해야겠죠. 이것은 대부분 정적으로 구성되기 때문에 Xib/Storyboard 상에서 결정하는 것이 편리합니다.

언어 현지화나 이미지 커스텀이 필요한 경우, 코드로 간단히 처리할 수 있습니다.

self.tabBar.items?[TABBAR_TABINDEX.HOME.rawValue].title = ResourceDataStore.strings().STRING_TITLE_PRODUCT
self.tabBar.items?[TABBAR_TABINDEX.HOME.rawValue].setTitleTextAttributes([NSAttributedStringKey.foregroundColor : UIColor.black], for: UIControlState())
self.tabBar.items?[TABBAR_TABINDEX.HOME.rawValue].image = ResourceDataStore.images().IMAGE_TABBAR_PRODUCT_NOR.withRenderingMode(.alwaysOriginal)

코드2 - TabBar Tab Name / Image Customization on Code

그리고 각각의 탭에 해당하는 ViewController를 지정하는데, 이 작업 역시 Xib/Storyboard 에서 할 수 있습니다. 정적인 화면일 때는 시각화하는 데 유용한 Xib/Storyboard를 주로 사용하는 게 좋습니다.


5. 그렇다면, 하이브리드는 어떨까요? Then, how about HYBRID?

앞서 언급한 두 컨트롤러의 차이점은 무엇일까요? 궁극적으로, 고객에게 서비스할 애플리케이션을 기준으로 보면 Navigation Controller나 TabBar Controller를 각각 단독으로 사용하는 것은 어렵습니다.

일반적으로 서비스에서 제공하는 기능들은 Navigation Controller 단독으로 처리하기에 화면 분류가 너무 다양하고, TabBar Controller만을 사용하기에도 플로우의 depth가 매우 깊은 경우가 대부분이기 때문입니다.

09
아주 복잡하죠?


그렇다면 유연하고 풍성한 서비스를 구성하려면 두 가지 컨트롤러를 함께 사용해야 한다는 결론에 도달합니다. 사실 이 이야기를 하려고 각 컨트롤러의 특성을 살펴본 것이기도 하고요.

브랜디 iOS 애플리케이션도 하이브리드 방식을 사용합니다. TabBar Controller를 루트에 두고, 각각의 Tab에는 Navigation Controller를 루트로 두어서 화면 플로우를 구성하는 방식입니다. 이렇게 애플리케이션을 구성하면 서로의 단점을 강력한 장점으로 커버할 수 있습니다.

먼저 더 이상 Navigation Controller의 초기 화면으로 돌아갈 걱정을 하지 않아도 됩니다. 이것은 TabBar Controller의 기본 기능 중 하나로, 해당 탭에서 화면 플로우를 타는 중에 Tab을 클릭하면 자동으로 Navigation Controller의 PopToRootViewControllerAnimated() function을 호출합니다. 따라서 Navigation Controller의 플로우 depth가 많이 깊어도 크게 고민하지 않아도 됩니다.

비디오4 - 현재 탭을 눌러 루트 뷰컨트롤러로 이동하기



다음으로, TabBar Controller의 Tab 개수만큼 서로 다른 Navigation Flow를 가질 수 있습니다. Navigation Controller만 사용하면 완전히 다른 종류의 화면 플로우를 시작하려고 해도 기존의 Navigation Controller에서 이어서 플로우를 시작할 수밖에 없고, 이전 화면으로 돌아가려면 현재의 화면 정보가 모두 메모리에서 삭제되기 때문에 정보의 동기화나 상태 보전 측면에서 치명적인 약점이 됩니다. 그러나 하이브리드 방식으로 TabBar Controller에 각각의 Navigation Controller와 플로우를 가지는 경우에는, 서로 다른 유형의 화면 플로우를 서로 다른 Tab에서 각각 수행할 수 있습니다.



예를 들어, Home 탭에서 상품 상세 정보를 보다가 나의 쿠폰이 얼마나 할인되는 쿠폰인지 확인하고 싶다고 가정했을 때, My 탭에서 쿠폰 목록을 보다가, 다시 Home 탭을 클릭하면 Home 탭에서 보던 상품상세 화면으로 돌아갈 수 있는 것입니다. 바꿔 말하면 이러한 플로우를 탭의 개수만큼 별도로 가져갈 수 있다는 뜻이기도 합니다. 사용자의 불편을 최소화하고, 데이터와 화면 상태를 유지하는데도 탁월한 방법입니다.

비디오4 - 탭 전환




6. 이제 뭐가 남았죠? What’s Next?

브랜디 iOS 앱은 TabBar Controller에 다섯 개의 탭을 구성하고, 각각의 탭 안에 Navigation Controller로 구현되는 화면 플로우를 가지는 구조로 구성되어 있습니다. 여기서 가장 중요한 부분은, TabBar Controller처럼 ‘보이는’ 방법으로 구현한 것이 아니라, 시스템에서 제공하는 TabBar Controller를 커스텀해서 사용했다는 부분입니다.

10
앱등이 부심


대부분의 쇼핑몰/커머스 앱은 하이브리드 방식을 채택하거나, 네이티브 앱으로 작성되었다고 해도 TabBar Controller를 사용하지 않는 경우가 많습니다. 이럴 경우, 위에서 언급한 TabBar Controller와 Navigation Controller를 동시에 사용하는 하이브리드 방식의 장점을 전혀 기대할 수 없습니다. 그렇게 ‘보이도록’ 만든 것일 뿐이기 때문이죠.

11
TabBar Controller에 Back버튼이라뇨?


iOS 애플리케이션을 개발할 때, 하이브리드 앱을 포팅해서 사용하는 방식은 최대한 ‘지양’하기를 권장합니다. 위에서 함께 살펴본 TabBar Controller나 Navigation Controller의 장점들을 충분히 사용하여 사용자들에게 풍족한 사용자 경험을 줄 수 있어야 합니다. “안드로이드 앱과 동일한 사용자 경험을 가지는 iOS 앱”이란 건 얼핏 듣기에 그럴 듯할지도 모르겠지만, 사용자가 iOS 애플리케이션에서 기대하는 것은 iOS에서만 누릴 수 있는 특별한 사용자 경험이라는 사실을 잊지 않길 바랍니다. 물론, 안드로이드 애플리케이션의 경우에도 마찬가지로 사용자들에게 안드로이드에서만 누릴 수 있는 사용자 경험을 줄 수 있는 방법을 고민해야겠죠.

다음 글에서는, Navigation Controller와 TabBar Controller를 커스터마이즈 하는 방법과 몇 가지 트릭들에 대해 공유하도록 하겠습니다. 부디 iOS 루키들에게 이 글이 조금이나마 도움이 되기를 기대하며, 글을 마칩니다.



이정환 과장 | R&D 개발MA팀
leejh@brandi.co.kr
브랜디, 오직 예쁜 옷만