본문 바로가기

iOS/학습정리

iOS) UIViewController

view를 다루는 것에 focus되어있는 controller

기본적으로 하나의 view property를 가지고 있다. 가끔 교체하는 경우도 있지만 안건드는 것이 좋다.

기본적으로 뷰 컨트롤러는 화면을 꽉 채우는 것이 목적이다. 화면을 보여주는 단위로는 스크린이 있다. 그 스크린 안에 윈도우라는 개념이 있다. 윈도우는 스크린에 들어가는 실제적인 뷰이다. 그 위에 올라가는 것이 이다. 기본적으로 화면을 보여주기 위해 세 가지 정도가 있다.

초창기에는 뷰 컨트롤러가 꽉 채운 화면만 되었는데 요새는 다른 역할도 한다.

ViewController와 MVC

MVC 패턴에서 C 역할을 하지만 뷰에 집중되어 있다. 화면 전체 콘텐츠를 담당하거나 특정 영역을 담당한다. 앱을 개념적으로 생각해보면 어떤 뷰컨트롤러 하나가 가지고있는 뷰를 보여주다 다른 뷰컨트롤러가 가지고 있는 뷰를 보여주는 형식이다. 이런 방식으로 앱은 View Controller 간의 흐름으로 구성된다고 볼 수 있다.

ViewController의 역할

뷰컨트롤러는 기본적으로 뷰 하나를 가지고 있고 그 뷰 아래에 여러 계층구조를 쌓아서 화면을 꽉 채우는 뷰를 만든다.
뷰의 계층을 관리해주면서 필요한 데이터를 화면에 어떻게 뿌릴지를 관리하는 중간에서의 매개체 역할을 한다.
화면 전체에 해당하는 사용자와의 상호작용을 담당한다. 뷰가 그 역할을 나눠가질 수도 있다.
뷰에 필요한 리소스 관리를 한다. 이미지, 음성, 진동, 메모리 등의 리소스를 관리한다. 화면 사이즈, 화면 회전에 대한 대응을 한다.

ViewController의 역할이 많아지면서 이를 어떻게 쪼갤것인가도 중요한 이슈가 된다.

앱의 사용성을 높이기 위해 Model과 View와 ViewController를 묶어서 재사용성을 높이는 것을 권장한다.

뷰는 사용자에게 보이는 화면, 사용자가 누르는 화면 그 자체만을 말한다.

UIViewController 주요 콜백

  • Did : 이벤트 발생 전
  • Will : 이벤트 발생 후
  • sholud : 선택사항

화면 관련

  • viewDidLoad()
  • viewWillAppear(Bool)
  • viewDidAppear(Bool)
  • viewWillDisappear(Bool)
  • viewDidDisappear(Bool)

회전 관련

  • var shouldAutorotate : Bool
  • var supportedInterfaceOrientations : UIInterfaceOrientationMask
  • var preferredInterfaceOrientationForPresentation : UIInterfaceOrientation

[View 재사용]
화면 자체를 재사용 하는 것이다. 자주 쓰는 화면 구조가 있다면 그 View Controller가 뜨는 것이다. 앨범에서 사진을 가져오는 ViewController인 UIImagePickerController가 전형적인 재사용을 위한 뷰 컨트롤러이다. 앨범이 가진 사진과 선택 화면이 있는 컨트롤러를 생성해서 호출하고 그 안에서 자동으로 선택한 다음 이미지만 넘겨주면 그것을 이미지 뷰에 바꿔치기 한다. 이미지뷰는 그냥 이미지만 보여주기 때문에 인터렉티브한 활동을 하려면 다른 것과 연결을 해야한다. IBOulet으로 연결하는 것은 수동적으로 값을 바꾸는 용도로 쓰고 IBAction의 경우 버튼에 연결한다.

[데이터 흐름]
Controller에서 입력을 하면 컨트롤러에서 ÌBAction을 호출하고 IBAction에서 로직이나 어떤 값을 처리한 다음 출력으로 뿌려준다.

splited_view

Root View Controller

화면을 가득 채우는 그 자체

ViewController 중에서 가장 뿌리가 되는 controller이다. 기본적으로 App을 실행하면 window가 자동으로 생긴다. 보통은 씬이나 AppDelegate와 같이 앱을 만들었을 때 생기는 템플릿 안에 기본적으로 윈도우가 생기는데, 그 윈도우가 rootViewController 속성을 가지고 있다.

iPad나 iPhone max의 경우 옆에 masterViewController라는 것을 둘 수 있다. window의 rootViewController가 splitViewController인 경우가 있다. 이 안에 두 개의 view controller가 더 있어서 총 세 개의 view controller가 있을 수 있다.

rootViewController는 화면을 가득 채우는 역할만 하고 실제 화면은 각각의 view controller의 view들이 보여지게 한다. 이런 controller를 container controller라 한다.

splited_view

Window

기본적으로 window가 하나 생기고 이는 기본적으로 검정색이다. window를 여러개 만들수도 있다. 그치만 iOS에서는 하나만 만들도록 권장하고 있다. mac이나 pc에서는 여러개의 윈도우를 만들 수 있지만 보통 iOS는 하나만 만드는 것을 권장한다.

챌린지 때 흰색 프레임을 만드는 것이 윈도우 컨셉이었다.

윈도우에 rootViewController를 지정해주면 해당 view가 window 위에 떠서 있다.

window

현재 xcode에서 window는 SceneDelegate 클래스에 들어있다. SceneDelegate는 AppDelegete 아래에 속해있다. iPad같은 경우 Scene이 여러개 있다고 가정하기 때문에 Scene마다 window가 있어 여러 윈도우가 생길 수 있다.

ViewController의 계층구조

view_debugger

프로젝트를 실행한 상태에서 view debugger를 통해 view의 계층구조를 볼 수 있다.

맨 뒤에 있는 것이 scene이고 눈에 보이진 않지만 화면을 어떻게 보여줄 것인지 모양을 알려준다. scene 아래에 window가 있고 그 다음 윈두우 아래에 TransitionView라는 것이 있고 그 다음 DropShadow라는 것이 있고 그 다음 viewController가 있다. 뷰 컨트롤러의 계층 구조는 화면상 보이진 않지만 이렇게 구성되어 있다.

뷰 컨트롤러 하나가 보여주는 화면을 scene이라 하는데 이는 위에서 말한 scene과는 다른 것이다. 뷰 컨트롤러가 보여주는 화면인 씬은 storyBoard에서 보여지는 하나의 화면을 말한다.

Custom View Controller

  • UiViewController Subclass
  • View 계층에 맞춰 관련있는 ViewController 다루기
  • 필요한 API 메서드 오버라이드 하기
    • viewDidLoad와 같은 것들
  • 자신만의 비즈니스 로직 추가
  • 앱의 동작 흐름에 맞추기
    • 다른 viewContoller를 present, push, pop, trasition 등

System View Controllers

Built-in UIKit View Controllers

  • Image Picker
  • Video Editor
  • Document Browser & Previewing iCloud Sharing
  • Shared Activities
  • Printer Picker
  • Word Lookup
  • Extra...

MVC

mvc_pattern

View Controller Containers

Parent ViewController

다른 뷰 컨트롤러를 포함하는 parent controller이다. 예로 TabBarController, NavigationController와 같은 것들이 있다. super와 sub의 관계와 비슷하게 parent와 child 관계가 있다. super와 sub의 관계는 상속할 때 생기는 관계이지만 parent와 child 관계는 상속관계가 아니라는 점을 주의해야 한다.

addSubview

루트 뷰 컨트롤러에 뷰가 화면을 꽉 채울 때 그 화면의 일부를 다른 뷰 컨트롤러의 뷰로 끼워 넣을 수 있다. 컨테이너 개념이 없던 예전에는 화면을 복잡하게 만들더라도 이렇게 하는 것이 익숙한 방식이었다.

before_container

이런 식으로 하면 보여질 수는 있지만 만일 OtherViewController가 메모리에서 사라진다면 소유하고 있는 뷰가 있더라도 사라져버린다. 이로 인해 초창기에 부작용이 많았다.

이러한 부작용을 해결하기 위해 뷰가 포함관계가 있듯이 뷰 컨트롤러도 포함관계를 갖도록 하였다.

고려해야 할 사항

  • 컨테이너(부모) 역할은 무엇이고, 자식들의 역할은 무엇인가?
  • 동시에 얼마나 많은 자식들이 보이나?
  • 형제 계층에 있는 뷰 컨트롤러들 관계들은 무엇인가?
  • 컨테이너에서 자식 뷰컨트롤러를 어떻게 추가하고 삭제하나?
  • 자식 화면의 위치나 크기가 변할 수 있나? 변화가 생기는 조건은 무엇인가?
  • 컨테이너가 직접 꾸미거나 내비게이션을 위해 제공하는 뷰가 있나?
  • 컨테이너와 자식 사이에 어떤 통신이 필요한가? UIViewController 클래스에 선언된 표준 이벤트가 아니라 세부적으로 다른 이벤트가 필요한가?
  • 컨테이너만 별도 다른 방법으로 표시해야 한다면 어떻게 해야하나?

viewContainerFlow

뷰 컨트롤 단위로 역할을 나누는 방법이 명확하지 않으므로 잘 고민하고 나눠야한다.

UIViewController_Flow

네비게이션 바에서 각 뷰는 메모리에는 남아있지만 모달로 present 되었다가 dismiss 되는 것이다. pop 하지 않는 이상 메모리에 계속 남아있다.