-
[UIKit] 뷰 생명주기(View Life Cycle)Apple🍎/iOS 2025. 1. 2. 13:03
뷰 관리 & 계층적 구조 (by UIViewController)
UIKit에서의 뷰 관리는 UIVIewController를 사용한다. 뷰의 계층적인 구조를 뷰 컨트롤러가 담당해 관리하기 때문에, 관리에 관련된 메서드나 속성을 UIVIewController(이하 줄여서 VC라고 하겠다)에 적용해 관리한다.
일반적으로 화면에 보여지는 것은 하나의 ViewController가 가진 View만 표시된다.
VC는 컨테이너 역할이므로 다른 View를 가진 다른 VC를 보여줄 수도 있고, 현재 VC에 다른 컨텐츠(View 객체들, UIButton,,)를 담을 수도 있다.보통 ViewController에는 Root View가 존재한다. window를 갖고 있는 곳이 RootViewController이며 View 를 로드할 때, window 사이즈를 채우도록 크기를 조정한다.
그러므로, View를 보여주기 위해선 ViewController가 반드시 필요하다.
이러한 VC를 스토리보드로 만든 경우 보통 자동으로 이 과정을 통해 연결된다.- 스토리보드에서 VC 로드 방법
- instantiateViewController(withIdentifier:) // 스토리보드로 생성한 VC 코드로 가져오기
- init(nibName:bundle:) // nib 파일 지정
뷰 동작 사이클
큰 흐름으로는 아래와 같다. (사이에 있는 viewIsAppearing의 경우 WWDC 23에 나온 내용으로 따로 정리하려 한다.)- viewDidLoad: 화면이 메모리에 로드 됨
- viewWillAppear: 뜰 예정 (손으로 새로운 화면을 넘기는 경우)
- viewDidAppear: 완전히 떴어요
- viewWillDisappear: 사라질 예정
*(animation으로 화면 전환 중인 상태, 손으로 옆으로 화면을 넘기고 있는 경우, 잡고 있으면 didDisappear 함수가 불리지 않음) - viewDidDisappear: 완벽하게 사라졌어요
이 사이클이 왜 중요하냐면, Modal, NavigationController, TabBar 등으로 화면이 전환되거나 나타낼때 각각 나타나는 생명주기 단계가 조금씩 달라진다.
크게 아래와 같이 나눠서 함수 호출 순서를 확인한다.- Modal
- Modal - Full screen
- Navigation - show, Tab bar
Modal
메인 홈 화면: Practice View Controller 이다.
일반 Modal의 경우 배경 VC를 없애는게 아니라 그 위에 Modal 뷰를 띄우는 것이기 때문에, 생각한대로 Modal의 뷰 사이클이 잘 나타난다.NavigationController, Modal(Full Screen)
반면, 모달뷰를 Full screen으로 보여주면 Navigation의 show와 같은 형태로 뷰가 사라지고 나타나는 것을 볼 수 있다.
Show 방식의 뷰 컨트롤러는 아래와 같이 다르게 생겨난다.
- Practice -> Show 화면 나올 때
Show(viewDidLoad) → Practice(viewWillDisappear, 사라질예정) → Show(viewWillAppear, 생길 예정) → Practice(viewDidDisappear, 없어짐) → Show(viewDidAppear, 완전히 나타남)
- Show가 back 버튼으로 다시 Practice로 돌아갈 때
Show는 Navigation이므로 화면에 띄우는 이전 뷰는 없어지고 새로운 뷰가 생기는 변화가 있다.
그러므로, 크게는 Practice 없어짐 → Show 생김 → Show가 사라질때 → 다시 Practice가 생김
Tab Bar
Practice(tab1), Second(tab2) VC로 구성된 tab bar이다.
- Practice(tab1) -> Second(tab2)를 눌렀을 때
second 뷰 로드 → second 나타날 예정 → practice 사라질예정 → second 나타남 → practice 사라짐
처음 second tab을 눌렀을 때는 navigation 방식처럼 똑같이 동작하지만, Tabbar의 경우 한번 로드된 view의 경우 메모리를 갖고 있어, viewDidLoad() 더이상 불리지 않는다.
Tab Bar 메모리 로드
메모리에 tab bar item은 한번 눌리면 계속 그 아이템은 메모리에 잡혀있기에 한번 눌린 2번째 페이지는 다음 눌렀을 때, viewWillAppear 부터 시작한다.
TabView의 특성상 하단에서 자주 불리는 View를 놓기 때문에, 메모리에 미리 잡아두는 것이다.메모리로 예를 들면, 각 Tab item이 100MB라고 했을 때,
처음엔 item 1만 메모리에 100MB 있다가, 2, 3, 4페이지를 누르면 400MB로 올라가있는 상태이다.하지만, 아이폰 메모리가 요새는 넘치기에 메모리를 걱정할 필요는 없지만, 성능을 위해 고려하면 좋을 것 같다.
예를 들어 MapKit의 경우 메모리를 많이 차지하는데 만약 tab view에 지도뷰를 보여주는 것을 넣어놓으면, 아래와 같이 앱 메모리가 확 늘어나는 것을 알 수 있다.
(그러므로 맵이 자주 보여지는 페이지 앱이 아니라면, show VC/modal로 구성할거같다)(좌)tab item1 만 눌렀을 때 (우) tab item 2, 3, 4를 다 누른 경우(map kit 포함) 지도를 show 페이지에 넣고, 돌아온 경우 메모리가 해제되는 것을 볼 수 있다.
그럼 실제로 VC 생명주기가 필요한 순간은 언제일까?
홈화면에 닉네임 표시 -> 다른 페이지에서 닉네임 수정 -> 홈화면에 다시 돌아왔을 때 반영
이 과정에서 홈화면에 돌아왔을 때, 닉네임이 변경 안되는 경우가 종종 있다. 이 경우 홈 화면이 viewDidLoad로 1번만 불려지기에 안될 수 있다.
만약 내용을 실시간으로 업데이트 하고 싶다면, viewWillAppear, viewDidAppear에서 변경하도록 해야한다.override func viewDidLoad() { super.viewDidLoad() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) view.backgroundColor = colorList.randomElement()! }
만약 변경되는 리소스가 너무 크면, 굳이 viewWillAppear에서 할 필요가 없다. willAppear의 경우 back 제스처로 움직일 때마다 호출되며 바뀌기 때문에 시점을 잘 생각하고 반영해야한다.
참고
https://developer.apple.com/documentation/uikit/uiviewcontroller#Manage-views (자세한 뷰 관리글 추천!)
'Apple🍎 > iOS' 카테고리의 다른 글
init(frame:), init(nibName: , bundle:), NSCoding (0) 2025.02.02 [iOS]Pagination & CollectionView prefetchItemsAt 사용 (0) 2025.01.16 [UIKit/스토리보드] IBOutlet weak & Collection은 왜 weak가 아닐까? (0) 2024.12.30 [iOS] Kingfisher & AppStorage로 이미지 다운로드 속도 개선하기 (0) 2024.11.24 [SwiftUI] Hashable, Equatable, Identifiable (0) 2024.11.10 - 스토리보드에서 VC 로드 방법