[iOS] ViewController 생명주기

나는 사과·2021년 3월 19일
0

TIL

목록 보기
8/17

iOS 개발자가 하고싶다는 사람이 ViewController의 생명주기조차 모른다고 하는게 부끄러워서 찾아보고 직접 예제까지 실행시켜보았습니다.

먼저, 이미지로 ViewController의 생명주기를 보면 다음과 같습니다.

viewDidLoad는 프로젝트를 생성하면 ViewController클래스에 포함되어있는 첫 함수이다. 그래서 익숙한데 나머지 다른 것들은 익숙하지 않을 것이다. 크게 보면 Load -> Appear -> Disappear 형태로 생명주기가 진행된다. 그 안에서 이 동작들이 발생하기 전에 호출되는지 발생한 후에 호출되는지 나눠진다. 간단하게 위의 생명주기에서 어떤 일이 일어나는지 알아보면 다음과 같다.

  • ViewDidLoad : ViewController가 메모리에 로드된 후 호출(시스템에 의해서 자동으로 호출된다.)
  • ViewWillAppear : View가 화면상에 나타나기 직전에 호출, View가 나타날 것이라는 것을 Controller에게 알림
  • ViewDidAppear : View가 화면에 나타난 직후에 호출, View가 나타났다는 것을 Controller에게 알림
  • ViewWillDisappear : View가 사라지기 직전에 호출, View가 삭제될 것이라는 것을 Controller에게 알림
  • ViewDidDisappear : View가 사라진 후에 호출, View가 삭제된 것을 Controller에게 알림

직접 코드로 구현해서 두개의 ViewController를 이동하면서 어떻게 호출되는지를 알아보자.

처음 실행시키면 첫번째 View의 viewDidAppear까지 호출이 된 모습이다. 그럼 여기서 다음 View로 넘어가는 버튼을 누르면 어떻게 될까?

첫번째 View의 viewDidAppear에 이어서 버튼을 누르면, 두번째 View가 메모리에 로드되는 viewDidLoad가 호출이 된 후에 첫번째 View는 viewDidDisappear이 호출이 되면서 Controller에게 이 뷰는 사라질 것이라는 것을 알린다. 그 다음 두번째 View의 viewWillAppearviewDidAppear이 호출이 되면서 두번째 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
    }
}

0개의 댓글