개발을 시작하는 이야기

StoryBoard를 사용하기 본문

개발 이야기/Swift

StoryBoard를 사용하기

Teiresias 2022. 3. 22. 18:08

프로젝트에 스토리보드를 적용해서 제작하게 되면 앱의 화면을 보다 쉽게 확인하며 제작이 가능하기 때문에 앱의 관리가 용이하다는 장점이 있지만 프로젝트의 규모가 커지고, 복잡해지기 시작하면서 다양한 어려움이 발생하게 된다.

스토리보드와 깔끔한 사용법에 대해 알아보고 정리해보도록 하자.

1. 스토리보드?

 스토리보드는 iOS 앱 화면 구성을 보다 직관적으로, 바로 보며 구성할 수 있도록 지원하는 기능으로 Xcode 4.2 버전부터 제공되고 있는 기능으로, 어떤 형태로 앱의 화면을 구성할지 특정 액션을 취했을 때 어떤 형태가 동작할 것인지 등의 앱 화면의 전체적인 흐름과 모양을 시각적으로 표현하고 확인할 수 있는 기능이다. 

스토리보드를 사용하여 작업을 하게 되면 편집기 영역을 자유롭게 설정하며 보다 편하게 작업을 진행할 수 있다.

2. StoryBoard의 장단점

스토리보드의 장점

  • 빠른 초기화 - 뷰를 제작하는 시간이 오래걸리지 않는다.
  • 시각화 - 뷰의 구조와 흐름을 한눈에 볼 수 있기 때문에 앱의 구조를 파악하기 쉽다.
  • 낮은 진입장벽 - 코드를 모르는 초보자도 뷰를 제작하기 용이함. (실제 교육과정에서 스토리보드를 활용하여 제작함)

스토리보드의 단점

  • 생산성 - 앱이 점점 커지면 스토리보드의 로딩 시간이 길어지게 되면서 오히려 생산성이 떨어짐
  • 가독성 - 스토리보드가 방대해지면 읽기가 어려워지고 난잡해 보여서 가독성이 많이 떨어짐
  • 협업의 어려움 - 스토리보드 파일이 다수의 인원이 수정을 하게 되면 Merge Conflict 처리가 큰 어려움으로 작용함
  • 재사용성 - 스토리보드로 만든 뷰는 재사용하기가 어렵다
  • 번거로움 - 스토리보드로 만든 뷰들을 코드와 연결하기 위해서는 Identifier를 부여해주어야 하는데 이를 매번 부여하고 관리해주는 일이 번거롭다.

3. 코드로 UI를 제작하는게 답인가?

 얼핏 보기에도 스토리보드를 활용하는 데 있어 장점보다는 단점이 많아 보인다. 그렇다면 코드로 UI를 작성하는 것이 해답인가?라고 한다면 당연히 '아니다'라고 할 수 있다. 요즘은 스토리보드를 활용하는 팀들도 많이 있는 것으로 알고 있고, 애플은 인터페이스 빌더에  많은 개선을 가져왔다. 사이즈 클래스는 더 직관적으로 사용할 수 있고, 스토리보드의 줌 기능과 프리뷰 보기의 활용은 편리함이 어마 무시하다. 하지만 여전히 인터페이스 빌더를 이용하여 복잡한 여러 뷰들을 연결하는 앱을 만들 때에는 단점들을 고려하여 사용에 유의해야 하는 점들이 있다. 

스토리보드로 프로젝트 진행하기

 단점과 장점이 명확하지만 그럼에도 스토리보드를 활용하여 프로젝트를 진행하고자 한다면 고려해야 하는 점을 살펴보자

TrandMedia 프로젝트를 시작하고 스토리보드를 활용하여 앱을 제작하기 시작했을때 나의 Main.storyboard의 모습. 뷰의 전체흐름을 쉽게 파악할 수 있어 좋아 보이지만 위에서 말한 문제들을 내포하고 있다.

 이정도 프로젝트의 규모에서는 빌드 속도의 차이라던가, 협업의 문제가 발생하거나 하지는 않았지만, 클릭을 하는 과정에서 컨스트레인트가 바뀌는 일이 발생한다거나, 뷰 컨트롤러 별로 스토리보드를 할당해주는 과정에서 실수가 발생할 확률이 있다. 그렇기 때문에 하나의 스토리보드만을 사용하기보다는, 여러 개의 스토리보드로 분리해서 사용하게 된다.

스토리보드 분리

 하나의 스토리보드에서는 세그웨이로 다른 뷰와 간단히 연결을 해줄 수 있지만 스토리 보드를 분리하게 되면 스토리보드를 연결해주는 두가지 방법을 활용해야 한다. 

  • 스토리보드 레퍼런스를 활용하는 방법
  • 스토리보드를 코드로 연결하는 방법

스토리보드 래퍼런스를 활용하는 방법은 이곳에서 자세하게 설명되어있고, 내가 사용했던 방법인 코드로 연결하는 방법에 대해 소개하겠다.

파일명 맞추기

 이것은 일종의 관습과도 같은 보편적인 네이밍 컨벤션일뿐만 아니라, 프로젝트의 파일을 관리 함에 있어 많은 도움이 되는 요소이다.

만일 스토리보드와 뷰 컨트롤러의 서로다른 이름을 가진 100개의 파일이 있다고 한다면 이를 기억하고 연결하고 관리하는 데 있어 더 많은 수고로움과 번거로움이 있음은 말하지 않아도 알 수 있을 것이다.

이니셜 라이징

뷰 컨트롤러에서 스토리보드를 이니셜 라이징을 할 때, 아래와 같은 코드를 만나게 된다.

let storyboard = UIStoryboard(name: “Main”, bundle: nil)
let homeViewController = storyboard.instantiateViewController(withIdentifier: “HomeViewController”)

보다시피 아주 깨끗해 보이는 코드는 아니다. 스토리 보드명도 필요하고, 해당 뷰 컨트롤러에 스토리보드ID도 설정해주어야 하는 과정들을 매번 뷰컨트롤러와 스토리보드를 만들때마다 해주어야 한다.

 

 더 나은 방법은 위 코드를 뷰컨트롤러 안에 옮겨 두고, static method를 사용하여 스토리보드와 함께 이니셜 라이징을 하는 방법이다.

class HomeViewController: UIViewController { 
      static func storyboardInstance() -> HomeViewController? { 
            let storyboard = UIStoryboard(name: “HomeViewController”, bundle: nil)
            return storyboard.instantiateInitialViewController() as? HomeViewController    
      }
}

그리고 스토리보드 아이디를 클래스 이름으로 설정하도록 한다.

extension NSObject{
	static func classNameToString() -> String {
    	return String(reflecting: type(of: self)).components(separatedBy: ".").last!
    }
    
    func classNameToString() -> String {
    	return String(reflecting: type(of: self)).components(separatedBy: ".").last!
    }
}

class HomeViewController: UIViewController {
	static func storyboardInstance() -> HomeViewController? {
    	let storyboard(name: classNameToString(), bundle: nil)
        return storyboard.instantiateInitialViewController() as? HomeViewController
    }
}

이와 같은 방법을 사용하면 이젠 이니셜 라이즈 할 때, 한 줄로 작성을 해줄 수 있다.

let homeViewController = HomeViewController.storyboardInstance()

하드코딩으로 스토리보드 아이디 설정하는 방법을 피할 수 있고, 클래스명을 활용해서 사용할 수 있어 에러를 줄일 수 있게 된다.

세그웨이 오버 라이딩

만약 그럼에도 불구하고 하나의 스토리보드에 여러 개의 뷰 컨트롤러를 넣을수밖에 없다 하더라도 세그웨이 관련 메소드 오버라이드를 하지 않는것이 좋다. 세그웨이는 각각의 이름을 지정해주어야 하고, 이는 에러를 유발하는 가능성이 점점 커지게 되는것을 의미한다. 그리고 prepareForSegue method는 세그웨이가 추가될때마다 점점 못생겨지고 읽기 어려운 코딩이 될것이다. 그렇기 때문에 다음 뷰 컨트롤러로 연결을 할 때, IBAction을 활용하여 메소드 안에서 뷰컨트롤러 이니셜 라이징을 해주는 것이 좋다.

@IBAction func didTapHomeButton(_ sender: AnyObject) {
    if let nextViewController = NextViewController.storyboardInstance() {
   // initialize all your class properties
   // homeViewController.property1 = … 
   // homeViewController.property2 = … 
   
   // either push or present the nextViewController,
   // depending on your navigation structure 
   
   // present present(nextViewController, animated: true, completion: nil) 
   // or push
   navigationController?.pushViewController(nextViewController, animated: true)
   }
}

참조한 페이지에는 추가적으로 Unwind segue에 대한 내용이 있지만 아직 이것에 대해서는 좀 더 탐구가 필요할 것 같다.

 

스토리보드 분할을 적용하여 변경된  Main.storyboard의 모습.

참조 : medium.com

'개발 이야기 > Swift' 카테고리의 다른 글

MVC(Model, View, Controller) 패턴  (0) 2022.03.24
XIB를 활용하기  (0) 2022.03.23
@main  (0) 2022.03.21
앱 시닝(app thinning)  (0) 2022.03.20
weak, unowned  (0) 2022.03.19