본문 바로가기
SwiftUI/SwiftUI Advanced

[SwiftUI] 링크도 게으름이 필요해: NavigationLink를 Lazy하게

by lody.park 2024. 8. 18.

안녕하세요. 로디입니다.

 

SwiftUI로 앱을 개발하다 보면 자연스럽게 만나게 되는 친구가 있죠. 바로 NavigationLink입니다.

오늘은 NavigationLink에서 메모리 사용을 최적화하는 기법에 대해 알아보려고 합니다.

 

뷰 간의 네비게이션을 손쉽게 처리해주는 NavigationLink 요녀석, 처음엔 아주 사랑스러운데, 쓰다 보면 뭔가 불편함을 느낄 때가 있습니다.

 

 

기본적으로 NavigationLink는 화면에 나타나는 순간, 링크의 목적지(destination)를 미리 생성해버립니다. 작은 화면이나 간단한 뷰라면 상관없지만, 복잡한 화면이거나 무거운 데이터를 다루는 경우라면 이야기가 달라집니다. 무거운 뷰를 미리 생성해둔다..? 메모리 폭행범인가요?..🥲

 

아직 쓰지도 않는 뷰의 메모리를 미리 잡아둘 필요가 있을까요?

필요로 할때 생성하도록 늦출 수는 없을까요?

 

여기서 등장하는 해결책이 바로 게으르게(Lazy) 목적지 뷰 생성하기입니다.

 

 

 

Lazy하게 목적지를 생성하는 것은, NavigationLink의 목적지 뷰가 필요할 때(즉, 사용자가 실제로 NavigationLink를 클릭하여 화면 전환이 발생할 때)만 해당 뷰를 초기화하는 원리입니다.

 

이를 통해 초기 렌더링 시점에서 불필요한 리소스 소비를 방지할 수 있습니다.

 

방법은 간단합니다. 목적지 뷰를 한번 감싸주기(wrapping)만 하면 됩니다.

wrapping을 위한 구조체를 구현해보겠습니다.

 

 

이 구조체의 핵심은 build라는 클로저입니다.

이 클로저는 LazyView가 실제로 사용될 때(즉, 뷰가 필요할 때)만 호출되어 뷰를 생성합니다. 이로 인해 NavigationLink는 링크를 클릭하기 전까지 목적지 뷰를 생성하지 않게 됩니다.

 

이제 NavigationLink의 목적지 뷰를 방금 정의한 Wrapper View로 감싸주겠습니다.

 

이제 다시 실행해서 메모리를 얼마나 잡아먹는지 보겠습니다.

 

엄청난 차이입니다. 

 

 

정리하자면,

 

복잡한 뷰, 무거운 데이터가 포함된 경우라면 Lazy하게 initialize 될 수 있도록 하는 것이 좋을 수 있습니다. 

다만, 모든 경우에 Lazy하게 하는 것이 꼭 정답은 아닙니다. 목적지가 가볍고 간단한 뷰라면, 굳이 Lazy하게 만들 필요는 없습니다. 오히려 이런 경우에는 즉시 생성하는 것이 더 간편하고 직관적일 수 있죠.  모든 곳에서 Lazy하게 뷰를 감싼다면 뷰 계층구조를 한번 더 복잡하게 만들어주는 것이기에 잘 따져서 사용해야합니다. SwiftUI에서 블록이 너무 많아서 가독성을 떨어뜨리니깐요 ㅎㅎ..