iOS 개발자가 하고싶다는 사람이 ViewController의 생명주기조차 모른다고 하는게 부끄러워서 찾아보고 직접 예제까지 실행시켜보았습니다.
먼저, 이미지로 ViewController의 생명주기를 보면 다음과 같습니다.
viewDidLoad
는 프로젝트를 생성하면 ViewController
클래스에 포함되어있는 첫 함수이다. 그래서 익숙한데 나머지 다른 것들은 익숙하지 않을 것이다. 크게 보면 Load
-> Appear
-> Disappear
형태로 생명주기가 진행된다. 그 안에서 이 동작들이 발생하기 전에 호출되는지 발생한 후에 호출되는지 나눠진다. 간단하게 위의 생명주기에서 어떤 일이 일어나는지 알아보면 다음과 같다.
직접 코드로 구현해서 두개의 ViewController를 이동하면서 어떻게 호출되는지를 알아보자.
처음 실행시키면 첫번째 View의 viewDidAppear
까지 호출이 된 모습이다. 그럼 여기서 다음 View로 넘어가는 버튼을 누르면 어떻게 될까?
첫번째 View의 viewDidAppear
에 이어서 버튼을 누르면, 두번째 View가 메모리에 로드되는 viewDidLoad
가 호출이 된 후에 첫번째 View는 viewDidDisappear
이 호출이 되면서 Controller에게 이 뷰는 사라질 것이라는 것을 알린다. 그 다음 두번째 View의 viewWillAppear
과 viewDidAppear
이 호출이 되면서 두번째 View가 화면에 출력이 되게 된다. 그러면서 첫번째 View는 viewDidDisapppear
을 호출하고 사라진다.
여기서, 다시한번 첫번째 View로 넘어가는 버튼을 누르게 된다면..
동일한 순서로 호출이 되게 된다.
정말 사소하고 쉬운 부분이라고 생각이 들 수도 있겠지만 이 부분을 놓쳤다는 것이 부끄럽다.
저는 두개의 ViewController간에 화면 전환을 통해서 생명주기를 알아봤다. ViewController가 아닌 NavigationController같은 경우엔 스택과 같은 형태로 진행이 되긴 때문에 첫번째 View의viewDidLoad
가 처음 호출이 되었으면 스택 안에 저장되어 있기 때문에 나중에 두번째 View에서 첫번째 View로 돌아가도 첫번째 View의 viewDidLoad
는 호출되지 않을 것이다.
예제 코드
// FirstView.swift
import UIKit
class FirstView: UIViewController {
let goNextViewBtn: UIButton = {
let button = UIButton(type: .system)
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("다음 뷰 GO GO~", for: .normal)
button.addTarget(self, action: #selector(goSecondView), for: .touchUpInside)
return button
}()
@objc func goSecondView(){
print("뷰1 - 버튼 Clicked")
let secondView = SecondView()
secondView.modalPresentationStyle = .currentContext
self.present(secondView, animated: true, completion: nil)
}
// 뷰의 컨트롤러가 메모리가 로드된 후 호출
override func viewDidLoad() {
super.viewDidLoad()
print("뷰1 - viewDidLoad 호출")
self.view.backgroundColor = .white
self.view.addSubview(goNextViewBtn)
layout()
}
override func viewWillAppear(_ animated: Bool) {
print("뷰1 - viewWillAppear 호출")
}
override func viewDidAppear(_ animated: Bool) {
print("뷰1 - viewDidAppear 호출")
}
override func viewWillDisappear(_ animated: Bool) {
print("뷰1 - viewWillDisappear 호출")
}
override func viewDidDisappear(_ animated: Bool) {
print("뷰1 - viewDidDisappear 호출")
}
func layout(){
goNextViewBtn.widthAnchor.constraint(equalToConstant: 250).isActive = true
goNextViewBtn.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
goNextViewBtn.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
}
// SecondView.swift
import UIKit
class SecondView: UIViewController {
let goFirstViewBtn: UIButton = {
let button = UIButton(type: .system)
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("처음 뷰 GO GO~", for: .normal)
button.addTarget(self, action: #selector(goFirstView), for: .touchUpInside)
return button
}()
@objc func goFirstView(){
print("뷰2 - 버튼 Clicked")
let firstView = FirstView()
firstView.modalPresentationStyle = .currentContext
self.present(firstView, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
print("뷰2 - viewDidLoad 호출")
self.view.backgroundColor = .white
self.view.addSubview(goFirstViewBtn)
layout()
}
override func viewWillAppear(_ animated: Bool) {
print("뷰2 - viewWillAppear 호출")
}
override func viewDidAppear(_ animated: Bool) {
print("뷰2 - viewDidAppear 호출")
}
override func viewWillDisappear(_ animated: Bool) {
print("뷰2 - viewWillDisappear 호출")
}
override func viewDidDisappear(_ animated: Bool) {
print("뷰2 - viewDidDisappear 호출")
}
func layout(){
goFirstViewBtn.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
goFirstViewBtn.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
}