본문 바로가기

학습 노트/iOS (2021)

118. Storyboard & Storyboard Reference

Storyboard

Storyboard는 단일 파일에서 다수의 화면을 구성할 수 있는 View Controller Graph 편집 도구이다.
Storyboard 이전에는 View Controller와 연관된 개별 Interface 파일을 생성했다.
이러한 파일을 Nib 파일이라고 부른다.
파일 내에서 단일 화면만 구성하기 때문에 파일 구조가 단순하고 크기가 작다.
그렇기 때문에 Interface Builder에서 지연 없이 편집할 수 있고, 하위 호환성이 높다.
반면에 화면의 흐름을 한 번에 파악하기어렵고, 다른 화면으로 이동하는 코드를 직접 작성해야 한다.

Storyboard는 단일 파일 내에서 View Controller와 연관된 Interface 파일을 구성하고, 화면 흐름에 따라 연결한다.
App을 구성하는 화면과 전체 흐름을 한 번에 파악할 수 있고, 연결된 화면 사이의 전환이 자동으로 처리된다.
또한 다른 Storyboard의 화면을 연결하는 것도 가능하다.
하지만, 파일 내에 다수의 화면이 포함되어있어서 Nib 파일에 비해 상대적으로 무겁다.
Mac의 사양이 낮다면 편집하는 시점에 지연이 자주 발생한다.
또한, 표현하는 정보의 양이 많기 때문에 화면이 작다면 편집이 불편하고, Team 단위 작업에서 Merge Complict가 자주 발생한다.

Xcode에서 새로운 프로젝트를 생성하면 Storyboard로 구성된 프로젝트가 생성된다.
기본 모델은 Storyboard지만 Nib파일을 함께 사용해도 문제가 없다.
자유롭게 선택해 사용할 수 있지만 Storyboard를 권장한다.
위에서 설명한 지연이나 Merge Complict가 문제가 된다면,
Storyboard를 기능이나 작업자 별로 분리하고 Sotryboard Reference로 연결하는 것으로 해결된다.

새 프로젝트를 생성하고, 왼쪽의 Document Outline을 확인하면 'Main.storyboard'가 생성된 것을 볼 수 있다.

Storyboard 파일에는 화면을 나타내는 객체가 추가되어있고,
이것을 Scene이라고 한다.

라이브러리에서 원하는 요소를 추가할 수도 있다.

Scene은 ViewController Class와 연결되어있다.
두 요소를 Target Action 메커니즘으로 연결하고, 이벤트를 처리한다.

Storyboard의 전체 편집 영역은 Canvas라고 부른다.
새로운 Scene을 추가할 때는 라이브러리에서 드래그해서 추가한다.

사진처럼 노란색 원형으로 표시된 아이콘들이 Scene과 관련된 항목이다.

새로운 View Contoller를 추가했다.

Storyboard의 장점은 Scene들을 연결해서 실행 흐름을 시각화할 수 있다는 점이다.
Scene들의 위에 표시되는 Bar를 Scene Dock이라고 부르고

가장 왼쪽의 아이콘을 선택하면 해당 Scene을 선택할 수 있다.

해당 아이콘에서 Ctrl를 누르고 드래그하거나 우클릭으로 드래그 해 Scene을 연결할 수 있다.

Present Modally를 선택하면 위처럼 연결된다.
두 Scene은 이제 Segue로 연결되었다.
Segue는 Scene의 흐름을 시각화하고, 화면 생성과 전환을 자동으로 처리한다.
첫 번째 Scene에서 Segue를 실행하면 연결된 Scene이 자동으로 생성되고, Modal 방식으로 화면이 표시된다.
Cocoa Touch Framework는 다양한 System Segue를 제공한다.

첫번째 Scene의 왼쪽에는 화살표가 연경 되어있는데,
해당 화살표는 Storyboard 내에서 '시작화면'을 의미한다.
시작화면으로 지정된 Scene을 Initial View Controller라고 부른다.
Storyboard에 존재하는 Scene들 중 하나는 반드시 Initial View Controller로 지정되어야 한다.

Initial View Controller를 변경할 때는 화살표를 드래그해 원하는 Scene으로 옮기거나,

원하는 Scene의 Attribute에서 Is Initial View Controller를 활성화하면 된다.

프로젝트 설정의 Main Interface 옵션을 변경해 앱에서 사용될 기본 Storyboard를 설정한다.
지금처럼 Main으로 설정되어있다면 앱 시작 시점에 같은 이름을 가진 Storyboard의 Initial View Controller를 자동으로 생성한다.

Storyboard는 개별 Scene을 식별할 수 있는 방법을 제공한다.
이를 Storyboard ID라고 부른다.

Scene을 선택하고 Identitiy Inspector의 Storyboard ID에서 설정한다.

이렇게 이름을 등록하면 해당 이름으로 Scene을 식별할 수 있다.

Code를 통해 Scene을 생성하기

첫 번째 Scene에 Button을 추가하고 Action을 연결한다.

//
//  ViewController.swift
//  StoryboardTestApp
//
//  Created by Martin.Q on 2021/11/06.
//

import UIKit

class ViewController: UIViewController {
	
	@IBAction func ButtonAction(_ sender: Any) {
		guard let vc = storyboard?.instantiateViewController(withIdentifier: "modalVC") else { return }
		present(vc, animated: true, completion: nil)
	}
	
	
	override func viewDidLoad() {
		super.viewDidLoad()
		// Do any additional setup after loading the view.
	}


}

UIViewController에서 제공하는 storyboard 속성은 현재 View Controller가 존재하는 Storyboard에 접근할 수 있는 속성이다.
해당 속성의 instantiateViewController 메소드를 사용해 씬에 접근할 수 있고,
파라미터로 Storyboard ID를 전달해 Scene을 식별한다.

이후 present 메소드를 사용해 전환을 진행한다.

 

Storyboard Reference

Storyboard를 여러 개로 분할하면 Stroyboard Reference로 Stroyboard에 접근해야 한다.
이번엔 Stroyboard를 나누고 연결해 본다.

분할할 Scene을 선택하고,
상단 메뉴에서 'Editor > Refactor to Storyboard'를 선택한다.
이후, 프로젝트 내의 원하는 폴더를 선택한 뒤 저장한다.

그러면 선택한 Scene이 새로운 Storyboard로 이동하고,

Main.storyboard 파일에는 원래 Scene이 존재하던 곳에 작은 박스 하나만 남겨져 있다.
이것을 Storyboard Reference라고 부른다.
Storyboard Reference는 다른 Storyboard에 있는 Scene을 연결한다.

Storyboard Reference의 Attribute를 확인해 보면
Storyboard는 Sub로 선택되어있고,
Referenced ID는 modalVC로 설정되어있다.
이것은 Sub.storyboard의 'modalVC'라는 Storyboard ID를 가진 Scene과 연결되어있다는 의미이다.
Referenced ID를 삭제하면 Sub.storyboard의 Initial View Contorller와 연결된다.

즉, 이렇게 비어있게 되면 오류가 발생하게 되고,
이유는 Sub.storyboard 파일에는 Initial View Controller가 존재하지 않기 때문이다.

이렇게 Sub.storyboard에서 Initial View Controller를 설정하게 되면 에러는 사라진다.

//
//  ViewController.swift
//  StoryboardTestApp
//
//  Created by Martin.Q on 2021/11/06.
//

import UIKit

class ViewController: UIViewController {

	@IBAction func ButtonAction(_ sender: Any) {
		guard let vc = storyboard?.instantiateViewController(withIdentifier: "modalVC") else { return }
		present(vc, animated: true, completion: nil)
	}
	
	
	override func viewDidLoad() {
		super.viewDidLoad()
		// Do any additional setup after loading the view.
	}


}

코드에서도 연결했던 modalVC라는 Storyboard ID를 가진 씬이 이동했기 때문에 수정해 줘야 한다.
해당 코드에서 storyboard 속성이 반환하는 Storyboard는 Main.storyboard이다.
이제는 modalVC라는 ID를 가진 Scene이 존재하지 않기 때문에 대상을 바꿔줘야 한다.

@IBAction func ButtonAction(_ sender: Any) {
	let subStoryboard = UIStoryboard(name: "Sub", bundle: nil)
	
	let vc = subStoryboard.instantiateViewController(withIdentifier: "modalVC")
	present(vc, animated: true, completion: nil)
}

다른 Storyboard에 접근하기 위해선 새로 인스턴스를 생성해 줘야 한다.
UIStoryboard(name:bundle:) 생성자는 첫 번째 파라미터로 Storyboard 파일의 이름을 문자열로 받고,
두 번째 파라미터로는 존재하는 bundle을 전달받는다.
지금은 동일한 bundle에 속하므로 nil을 전달한다.

이어서 대상 Storyboard를 storyboard 속성을 통한 Optional Binding에서 subStoryboard 인스턴스로 지정하는 것으로 수정한다.

Storyboard 직접 추가하기

Xcode의 Refactor 메뉴를 사용하지 않고, 직접 생성하는 것도 가능하다.

Document Outline에서 원하는 폴더에서 우클릭 한 다음,
New File 메뉴를 선택해 Storyboard를 생성할 수 있다.

새롭게 생성된 Scene을 해당 Storyboard의 Initial View Controller로 지정한다.

그리고 구분할 수 있도록 Background Color를 변경해 준다.

다시 Main.storyboard로 돌아와 Button을 하나 더 생성한다.

이후 라이브러리에서 Storyboard Reference를 선택해 Canvas에 추가하고,

Storyboard를 방금 새로 생성한 Storyboard로 지정한다.

이후 주번째 버튼을 드래그해 Modal 방식으로 연결하면 된다.