2015년 12월 10일 목요일

[iOS] 여러 스토리보드에서 시작점을 고르기

제목이 좀 뜬구름 잡기인 듯 한데 좀 더 쉽게 풀자면 이렇다:
  1. 프로젝트에 스토리보드가 두 개다. 이 중 하나는 튜토리얼용으로 앱 시작 시 한번만 보여줄 것이다. 이걸 스토리보드 하나로 만드면 너무 복잡해서 나눈 것이다.
  2. 앱 시작 시 특정 조건의 경우에는 튜토리얼용 스토리보드의 UI로 시작해야 한다.
  3. 그런데 어떻게 해야하지?
그냥 딱딱하게 설명할까 했지만 이번엔 좀 수고를 들여서 메모를 만들어 본다 -_-;

1. 스토리보드 추가

예제에서는 뷰 기반 프로젝트를 하나 만들어서 진행한다. 문제에서 요구한 대로 기존의 Main.storyboard 라는 스토리보드가 있는 상태에서 New File을 이용해 다른 스토리보드를 추가한다.
파일 이름은 마음대로 이저도 되겠지만 여기서는 의도 대로 'Tutorial.storyboard' 라는 이름으로 지었다.

2. 스토리보드에서 엔트리 포인트 삭제

엔트리 포인트라 적었는데 그냥 '시작점' 이라는 의미다. 스토리보드 내에서는 Initial View Controller 라는 이름으로 칭한다.

메인 UI를 만들 스토리보드(예제에서는 Main.storyboard)를 열어서 화살표로 표시되는 Initial View Controller를 찾아서 이 옵션을 꺼준다. 즉 스토리보드에서 Initial View Controller를 없애버린다.
위 스크린샷 처럼 우측 인스펙터 영역에서 View Controller 하단의 Title 하단에 있는 Is Initial View Controller 항목의 체크를 해제하면 된다.

만약 스토리보드가 복잡해서 Initial View Controller가 어디에 있는지 못 찾겠다면 아래 스크린샷 처럼 뷰컨트롤러 좌측에 일반 세그(Segue)가 아닌 화살표를 찾아보자. 이제 뷰컨트롤러 좌측에 붙어있다면 그 화살표가 Initial View Controller를 가리키는 것이다.
이 뷰 컨트롤러를 찾아서 Initial View Controller 체크를 해제하면 좌측의 화살표가 사라진다.

이제 스토리보드의 엔트리포인트가 사라졌다. 앱을 실행시키면 아마도 죽거나 빌드할때 에러가 나거나 등등 아주 볼만한(?) 광경이 벌어질 것이다.

3. 메인 인터페이스 제거

프로젝트 설정에 들어가서 Main Interface 항목을 지워버린다.
리스트에는 없으나 그냥 딜리트 키를 눌러서 지워버리면 된다.

이제 아예 메인 인터페이스가 없어졌다. 앱의 UI가 완전히 사라져 버린 셈이다.

4. UI 만들기

이제 원하던데로 새로 추가한 스토리보드(여기서는 Tutorial.storyboard)에서 원하는 UI를 만든다.

예제에서는 첫 뷰 컨트롤러만 만들었다. 실제론 원하는대로 아무렇게나 아무거나 View Controller 혹은 그 하위클래스 타입이면 관계 없다.

물론 Initial View Controller 는 체크하지 말자.

5. 스토리보드 ID 붙여주기

기존의 엔트리 포인트를 삭제해 버렸기 때문에 이를 대체하기 위해서 시작할 때 뜰 뷰 컨트롤러의 Storyboard ID를 만들어야 한다. 그래야 코드로 이 뷰 컨트롤러를 생성할 수 있기 때문이다.
우측 인스펙터에서 Identity 섹션에서 스토리보드 ID를 만들어 줄 수 있다. 여기다 원하는 이름으로 마음껏 적으면 된다.

이런 식으로 시작점이 되는 모든 뷰 컨트롤러에 Storyboard ID를 만들어준다. 위의 스크린샷은 Tutorial.storyboard 에서만 했는데 기존UI(Main.storyboard) 에서도 Initial View Controller에 해당하던 뷰 컨트롤러의 Storyboard ID 를 만들어 줘야 한다.

예제에서는 StoryboardTutorialID 와 StoryboardMainID 라고 이름을 지어줬다. 물론 문자열이기 때문에 원하는대로 마음껏 지어도 된다. 개인적으로는 뷰 컨트롤러 소스 코드를 만들어 두고 이 클래스의 이름을 그대로 ID로 쓴다. 물론 취향이다. -_-

6. 코딩 타임

이제 스토리보드의 인스턴스를 만들고 시작점에 해당하는 뷰 컨트롤러 인스턴스를 가져오는 것을 해 볼 차례다.

여기서는 AppDelegate의 application:didFinishLaunchingWithOptions 를 코딩한다. 아래는 Swift로 구현한 예제이다. 시작점을 Tutorial.storyboard를 이용하도록 코딩한다.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
  // window가 없으니 만들어준다.
  self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
        
  // 스토리보드 인스턴스
  let tutorialStoryboard = UIStoryboard(name: "Tutorial", bundle: nil)
  // 뷰 컨트롤러 인스턴스
  let viewController = tutorialStoryboard.instantiateViewControllerWithIdentifier("StoryboardTutorialID")
        
  // 윈도우의 루트 뷰 컨트롤러 설정
  self.window?.rootViewController = viewController

  // 이제 화면에 보여주자.
  self.window?.makeKeyAndVisible()
        
  return true
}
프로젝트 설정에서 메인 인터페이스가 빠졌기 때문에 Xcode가 자동으로 해 주던 것을 코드로 만들어야 한다. 윈도우를 만들고 보여주는 코드는 이런 이유로 추가된 것이다.

그 외에는 기존의 스토리보드를 코드로 다루던 것과 큰 차이는 없다.

만약 조건에 따라 다른 스토리보드를 띄우고 싶다면? 그건 알아서 코딩하면 될 것이다. 스토리보드 로딩하고 여기서 뷰 컨트롤러까지 불어들이는 방법은 안다면 나머지는 ID만 바꿔주면 되는 문제다.

동일하게 이 코드가 이해되었다면 이제 Main.storyboard 로 전환하는 것은 어떻게 해야 할지 감이 잡힐 것이다. 사실 코드가 윈도우와 ID 관련 부분만 다르지 거의 같기 때문이다.
func switchToMainUI() {
  let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
  let viewController = tutorialStoryboard.instantiateViewControllerWithIdentifier("StoryboardMainID")
  self.window?.rootViewController = viewController
}
위 코드도 AppDelegate에 위치한다고 치자. 핵심 부분은 완전히 동일하다.

7. 추가사항

위 코드에 단점이 있다면 rootViewController를 직접 세팅하는 거라 장면전환(Transition) 애니메이션을 쓰기가 까다롭다는 점이다.

개인적으로는 rootViewController를 더미로 하나 만들어두고 여기서 자식 뷰 컨트롤러(Child View Controller)로 세팅해서 필요한 뷰 컨트롤러의 뷰를 추가하는 방식이 애니메이션 처리하기에는 수월할거라 생각한다.

댓글 없음 :