Custom ViewController 만들기를 주제로
Custom ViewController 를 만들 때 필요한 절차들에 대해 다룸
- Defining Your UI
- Handling User Interactions
- Displaying Your Views at Runtime
- Managing View Layout
- Managing Memory Efficiently
ViewController 의 UI를 구현하는 방법 2가지
애플 문서에서는 코드보다 뷰 계층을 시각화 할 수 있는 스토리보드를 좀 더 강조한다.
하지만 어떤게 절대적으로 좋다기 보다는 각자의 장단점이 존재한다
장점
단점
로드하고 파싱하는 과정에서 오버헤드 발생
스토리보드 파일이 커질 수록 로딩 시간이 길어진다.
작업이 번거롭고 연결이 누락되는 경우 crash가 발생한다. (스토리보드-코드 연결, identifier 등)
Merge Conflict가 잦고 발생시 해결하기 어려움(XML파일이기 때문)
Merge Conflict 문제 해결하기
화면 단위로 스토리보드 파일을 분리하고 같은 화면에서 사용 되는 비교적 복잡한 View 들은 Container ViewController 단위로 나누어 스토리보드 파일을 분리하여 관리할 수 있다.
장점
단점:
출처: https://yagom.net/forums/topic/현업에서-ui-구성할-때-스토리보드-vs-코드-그-승자는/
ViewController 는 Responder Object 로서 이벤트에 응답하고 이를 처리할 수 있지만 일반적으로 이를 직접 처리하기 보단 아래와 같은 방법을 사용한다.
: UIButton, UISwitch, UIStepper 등 UIControl 을 상속 받은 컨트롤 객체에 이벤트가 발생할 시 target-action 패턴을 사용하여 target(일반적으로 ViewController)의 action method 를 호출
- 스토리보드로 @IBAction method 사용
- addTarget()을 통해 @objc method 사용
: UIResponder.keyboardWillHideNotification 같이 시스템 혹은 다른 객체(보통 MVC에서는 Model)로부터 오는 notification 을 관찰하여 ViewController 를 업데이트한다.
: ViewController 는 다른 객체의 Delegate, Datasource 의 역할을 한다.
: (MVC) View 에 이벤트가 발생할 경우 target 인 ViewController 의 action method 를 호출하고 ViewController 는 이 input을 알맞은 Model 에게 전달하고 Model 이 처리한 값을 통해 ViewController가 UI를 갱신
이 때 Model 에게 직접 반환을 받게 되면 (객체의 변경에 영향을 받기 때문에) 두 객체간 결합도가 높아진다. 따라서 다음과 같은 방법을 사용하여 결합도를 낮출 수 있다.
1:1 관계
두 방법 모두 동일한 기능을 구현할 수 있지만 각자의 장단점이 존재
Delegate
vs Callback closure
: Delegate는 사용하기 위해 필요한 작업이 Callback closure 에 비해 많은 편이다.
필요한 작업: Protocol 을 만들어주고 Method 를 적어주고 ViewController 의 extension 에서 Protocol 을 채택
반면 Callback Closure 는 위 작업으로부터 비교적 자유롭다.
또한 어떻게 사용하느냐에 따라 다르긴 하지만 Model 의 method 에 callback closure 를 넘겨서 사용하는 경우 코드의 지역성을 통해 코드를 쉽게 이해할 수 있다.
- 따라서 다양한 종류의 이벤트를 처리해야해서 여러 종류의 Callback이 필요한 경우 Protocol을 사용하는 **Delegate**,
- 소수의 Callback이 필요한 경우에는 **Calback clsoure** 를 사용
1:N 관계
notification
: 여러 객체(보통 ViewController)에게 이벤트 발생을 알려줄 때 적합
Ex) iOS13이후의 아이패드에서 Multiple window 데이터 동기화
출처: https://zeddios.tistory.com/811
하나의 프로세스지만 2개의 Scene이 존재
KVO, didSet, willSet
...view의 크기, 위치가 바뀌어 레이아웃 프로세스가 진행될 때 UIKit 은 다음과 같은 과정을 진행한다.
필요에 따라 viewcontroller 의 trait collections 를 업데이트한다.
- trait collections
UITraitCollection: iOS의 인터페이스 환경을 나타내는 trait 들의 모음
size classes(regular, compact), Appearance, 3d Touch의 가능 여부까지 담고 있음
iOS12부터 라이트/다크모드 관련 프로퍼티(userInterfaceStyle) 또한 추가됨
Rotate 뿐 아니라 다크모드↔라이트모드 전환 시 호출됨
참고
ViewController 의 viewWillLayoutSubviews 를 호출
현재 UIPresentationController 객체의 containerViewWillLayoutSubviews 호출
ViewController 의 root view 의 layoutSubviews 호출
ViewController 의 viewDidLayoutSubviews 호출
현재 UIPresentationController 객체의 containerViewDidLayoutSubviews 호출
UIPresentationController
(애플 문서)
containerView
(애플 문서)
: transition 과정에서 presented 및 presentingController 의 view의 superview
viewWillLayoutSubviews
, viewDidLayoutSubviews
layoutSubviews
: View와 subView들의 크기, 위치를 조정, 즉 레이아웃을 조정하는 Method
출처: https://tech.gc.com/demystifying-ios-layout/
다음 업데이트 사이클까지 기다리는 방법
setNeedsLayout()
view의 사이즈 변경 / subview 추가 / device 회전 / UIScrollView 스크롤 시 / view의 constraint 변경
layoutSubviews()
가 호출됨즉시 호출하는 방법 (layout 변경 시점과 실제 업데이트 시점이 다르기 때문에 필요)
layoutIfNeeded
: 다음 업데이트 사이클까지 기다리지 않고 layoutSubviews 를 즉시 호출. 하지만, 위에서 언급한 방법들에 의해 flag가 활성화 되지 않은 경우 layoutSubviews 는 호출되지 않는다.+ → Top, Bottom Layout Guide 활용
iOS11부터 Safe Area Layout Guide 활용
init
viewDidLoad
didReceiveMemoryWarning
dealloc
deinit