기존의 방식대로 모든 화면에 대한 스토리보드를 만들고, 코드를 집어넣어 완성하고자 하였다.
기존의 방식대로 하면서 항상 느껴왔던 문제점이 이번 구현으로 더욱 심해진 것을 느꼈다.
항상 느껴왔던 문제점이란 코드, UI 및 뷰 컨트롤러의 너무 심한 중복이다.
또한 스토리보드를 벗어나 구현을 해보고 싶은 마음이 생긴 것도 조금 있다.
3가지 종류의 요구사항이 모두 비슷한 틀, 비슷한 기능을 가지고 있고
심지어 아예 동일한 기능을 하는 것들이 꽤 있기 때문에 중복을 최대한 피하고 싶었다.
가장 단순하게 찾을 수 있는 UI의 공통된 요소가 무엇이 있을까?
상단의 UINavigationBar
하단의 이전 문제, 다음 문제 버튼
이 공통 요소들을 ExamRootViewController
에서 구현하고,
3가지 종류의 요구 사항에 대한 뷰 컨트롤러가 ExamRootViewController
을 상속하게 하였다.
이렇게 하여 기본적인 틀은 마련이 되었다.
단순한 UI의 공통점은 그렇다 하지만, 그 공통점들을 제외하고 비슷한 점들은 무엇이 있을까?
이 뷰는 비슷하긴 하지만, 똑같지 않다. 똑같지는 않지만, 너무 비슷하다.
이를 각각의 뷰에 레이아웃 제약을 걸어서 넣는다면, 이전 문제와 다음 문제 버튼을 누르면
애니메이션을 어떻게 줄 것인가? 애니메이션을 주지 않는다 해도 어떻게 전환할 것인가?
이를 ContainerView
로 지칭하고, 프로토콜로 정의하였다.
enum ExamType { case create, take, history }
protocol ContainerView: UIView { ... }
class CreateQuestionContainerView: UIView, ContainerView { ... }
class TakeExamContainerView: UIView, ContainerView { ... }
class ExamHistoryContainerView: UIView, ContainerView { ... }
또한 ExamType
과 Question
을 전달받아 적절한 ContainerView
를 반환하는
ContainerViewFactory
를 정의하였다.
class ContainerViewFactory {
public static func getContainerView(of type: ExamType, question: Question?) -> ContainerView {
...
}
}
이로써 ContainerView
를 사용하는 입장에서는 ExamType
과 Question
만 던져 주면
그에 알맞은 ContainerView
를 얻을 수 있게 되었다.
얻은 뷰로 애니메이션을 구현할 수도 있고, 전환이 매우 편해졌다.