view controller life cycle
를 검색하면 SwiftUI 나 UIKit 에서의 view 의 생명 주기에 관련된 내용을 많이 찾아볼 수 있습니다. 특히 UIKit 의 경우에는 UIViewController Lifecycle 이라는 제목과 함께 아래의 사진이 가장 많이 활용되더라구요. (원출처가 어디일까 궁금하네요..)
사실 처음 개발 공부를 시작했을 때는 생명주기라는 표현이 참 낯설었습니다. 차라리 life cycle 이라는 영어 단어가 조금 더 쉬웠을 정도로요.
생명 주기란 쉽게 말하면 무언가가 생성되고 관리되다가 소멸되는 일련의 과정입니다. 사람이 태어나서 인생을 살다가 죽음에 이르는 것처럼, 우리가 만드는 앱, 데이터, 뷰와 같은 것들도 생성되고, 활용되다가, 소멸되는 과정을 거친다는 것이죠. 개발자가 작성한 코드는 실행되는 과정에서 적절한 시점에 메모리에 올라가는 것으로 생성되고, 활용되는 동안 메모리에 머물다가, 최종적으로는 쓰임을 다하게 되면 메모리에서 해제되는 것으로 그 생명을 다하게 됩니다.
이런 개념으로 위 이미지를 다시 살펴보겠습니다. view 의 생명 주기를 생성과 활용, 소멸이라는 3가지 단계로 나눈다고 한다면, init 에서 viewDidLoad 까지의 과정은 생성에 해당됩니다. 그런 뒤에 viewWillAppear 에서 viewDidDisappear 까지의 과정을 반복하며 활용되죠. 그리고 viewDidUnload 를 통해 최종적으로 소멸된다고 볼 수 있습니다.
처음에는 viewDidLoad 메서드에서 화면의 데이터가 업데이트 되도록 로직을 구성했었습니다. 근데 다른 화면으로 이동했다 돌아올 때 화면이 새로운 데이터를 반영하지 않더라구요. viewDidLoad 메서드는 뷰가 처음 로드될 때만 동작하는 메서드이기 때문이었습니다.
그렇다면 화면의 데이터가 업데이트 되는 로직은 어느 시점에서 실행되어야 할까요? 여러 블로그에 보니 viewWillAppear 에 넣기도 하고, viewDidAppear 에 넣기도 하고 조금씩 다른 견해들이 있더라구요.
공부하는 입장에서 이럴 때는 언제나 공식 문서에 의존하라고 배우게 되는데요. 앱의 life cycle 과 관련된 아티클은 검색이 되는 반면에 view controller 의 life cycle 에 관해서는 검색이 잘 되지 않아서 조금 애를 먹었습니다. 그렇게 제가 찾아낸 나름의 근거가 되는 문서가 바로 이 문서입니다.
문서 자체에 꽤나 상세하게 설명이 되어 있으니, 전체를 다 다루지는 않을 예정입니다. 여기에서는 데이터가 언제 화면에 연동되어야 하는지에 관련된 부분들만 언급을 해볼까 해요.
문서를 읽다 보면 다음과 같은 부분이 나타납니다.
At load time, perform only the one-time configuration steps you need to prepare the view controller for use. Use load time to create and configure any additional views that aren’t part of your storyboard. Don’t perform tasks that need to happen each time your view controller appears onscreen. For example, don’t start animations or update the values of views.
로드 타임에는 화면에 매번 반영되어야 하는 작업을 수행하지 말라고 되어 있습니다. 예시에도 친절하게 update the values of views 와 같은 작업을 언급하면서 이를 하지 말라고 말해주고 있죠.
viewDidLoad() 에서 데이터를 업데이트 해주는 것은, 어차피 초기 한번만 실행되는 작업일 뿐이기 때문에도 문제가 되지만, 애초에 부적절한 작업의 형태라는 것을 알 수 있습니다. 그렇다면 언제 하면 좋을까요?
조금 더 아래에 가보면 view controller 가 어떤 과정으로 레이아웃을 업데이트하는지가 나오는데요. 이 과정에서 굉장히 다양한 메서드가 불린다는 것을 알 수 있습니다. 저는 viewWillAppear, viewDidAppear 메서드에서 데이터를 업데이트 하도록 작성해 보았는데요. 크게 문제가 있지는 않았습니다만, viewDidAppear 메서드에 넣은 경우 화면이 노출된 이후에 한 번 깜박! 하면서 데이터가 업데이트되는 문제가 있었습니다. 화면 전환이 매끄럽지 않다는 느낌이었죠.
사실 viewWillAppear 에서 데이터를 업데이트 한다고 해도 앱은 문제 없이 동작하긴 했습니다. 하지만 문서는 viewIsAppearing 메서드를 활용하라고 말하고 있습니다. 그리고 그 근거까지도 설명하고 있죠.
Update the content of your views in the viewIsAppearing(:) method of your view controller. When the system calls this method, it has already added the view to the view hierarchy and defined the frame, bounds, margins, and insets. Content that the system adds in viewIsAppearing(:) displays when the view is first visible on the screen.
뿐만 아니라 viewIsAppearing 메서드는 레이아웃 메서드와는 달리 모양 전환(appearance transition?)이 진행될 때 단 한번만 호출된다고 합니다. 매번 반복되어 호출되지 않는다는 것이죠. appearance transition 이 정확히 무슨 의미인지 아직 이해되지는 않았지만, 중요한 점은 데이터와 관련 없는 메서드가 호출될 때마다 데이터를 변경해줄 필요가 없으니 콘텐츠의 변화는 viewIsAppearing 메서드에 담아두면 된다는 점이 아닐까 합니다.
The system calls the viewWillLayoutSubviews() and viewDidLayoutSubviews() methods, whenever the view performs layout, which can happen at any time while the view is visible. Because the system calls viewIsAppearing(_:) only once as part of each appearance transition, changes you make in this method don’t repeat each time the view performs layout.
참고로 화면전환이 내비게이션이 아닌 모달 방식인 경우에는 모달을 호출한 뷰컨트롤러의 생명주기 메서드들이 동작하지 않습니다. 이 경우 위임(Delegate) 패턴을 활용해 문제를 해결할 수 있는데요. 이 내용은 언젠가 조금 더 공부가 되면 한번 정리해 볼까 합니다.
늘 그렇듯 이 글이 누군가에게 도움이 되기를 바랍니다. 감사합니다!