[WWDC 23 / SwiftUI] Demystify SwiftUI Performance with Dependencies

박준혁 - Niro·2023년 12월 3일
1

WWDC

목록 보기
7/11
post-thumbnail

안녕하세요 Niro 🚗 입니다!

🔗 [WWDC 23 / SwiftUI] Demystify SwiftUI Performance with FeedBack Loop

첫번째 편으로 갈수록 다양한 기능을 담고 있는 App 에서 문제가 발생했을 때 빠르게 대처할 수 있는 FeddBack Loop 에 대해 알아보았습니다.

성능 문제를 해결하는 프로세스를 배웠으니 이제는 진짜로 해결하는 방법을 알아야겠죠?

[WWDC 23] - Demystify SwiftUI Performance 세션의 두번째 주제인 Dependencies - 의존성에 대해 알아보고자 합니다!


🔁 의존성을 확인해보자

자, 귀여운 강아지를 보여주는 상세 View 가 있네요!

dog 를 매개변수로 받고 PlayTime 여부를 알기 위한 Environment 프로퍼티를 갖고 있습니다.

두 프로퍼티는 View 의 종속성을 의미하며 그래프로 나타내면 다음과 같습니다.

DogView 는 VStack 을 생성하고 VStack 은 위와 같이 여러 자식을 갖고 있습니다. 이와 같이 쭉 그래프는 확장이 되고 Image, Text, Color 와 같은 최종적인 View (leaf View) 에 도달할때 까지 계속 이어지겠죠?

다시 앱을 돌아가보니 뭔가 화면이 바뀐거 같습니다. SwiftUI 에서는 Model 에서 데이터가 변경되면 View 가 업데이트가 되는 특징을 갖고 있습니다.

우리는 여기서 데이터 변화가 있을 때 View 가 어떻게 업데이트 되는지에 대해 깊이 알아볼 필요가 있습니다.

위의 그래프에서 자식 View 들은 부모가 생성하는 View 를 기준으로 의존적입니다. 이렇게 View 끼리도 의존적이지만 Dynamic Property 도 또 다른 형태의 의존성의 일반적인 예시입니다.

예를 들어 DogView 는 @Environment Property 를 통해서 isPlayTime 을 읽어오게 되어있는데 이것은 부모 View 로 부터 생성된 값 뿐만 아니라 environment 의 값에도 종속적이게 되는 것이죠!

이것을 시각화 해봅시다!
X 축을 시간이라 두고 업데이트의 프로세스 첫번째 단계는 바로 View 를 위한 새로운 값을 생성하는 것입니다.

즉, dogisPlayTime 프로퍼티와 같이 모든 저장 프로퍼티를 의미합니다.

그 다음 SwiftUI 는 View 의 모든 동적 프로퍼티를 업데이트하게 되고

업데이트된 값으로 body 가 실행되어 View 의 자식들을 실행하게 되죠!

이런 과정은 UI 를 업데이트하기 위해 재귀적으로 반복이 되고 변경된 종속성이나 새로운 값이 있는 View 만 업데이트하게 됩니다.

Dog 라는 Model 은 구조체로 이루어져 값이 변경되면 새로운 복사본이 생성이 됩니다. 그러면 DogView 는 Stack 에 대한 새로운 컨텐츠를 생성하고 Stack 의 하위 항목들을 업데이트 하게 되는 거죠!

이렇게 변경된 ScalableDogImage 는 새로운 이미지를 생성하게 되고 Image 는 leaf View 이기 때문에 여기부터는 SwiftUI 가 작업을 진행하게 됩니다.

이것이 바로! 의존성 그래프를 보는 방법이고 이러한 프로세스를 개선하기 위해 몇가지 팁을 살펴보고자합니다.


♻️ 바뀌는 이유를 찾아보자

자, 우리는 방금 View 가 업데이트 되는 과정을 살펴보았습니다. 굉장히 복잡했는데.. 이러한 과정을 줄인다면 더욱 좋겠죠?

SwiftUI 에서는 View 가 업데이트 되는 시기를 이해하기 위해 printChanges 라는 메서드를 제공하는데 해당 메서드를 통해 SwiftUI graph evaluator 가 특정 View 의 body 를 왜 호출했는지를 출력할 수 있게 됩니다.

예시를 볼까요?

State 가 포함된 ScalableDogImage 가 있습니다. Image 를 탭하게 되면 State 프로퍼티인 scaleToFill 이 바뀌게 되고 이미지가 커지게 되는 것이죠!

지금 View 의 body 에 breakPoint 를 걸어보았습니다.
그럼 우리는 이처럼 llDB 콘솔을 사용할 수 있게 되는데 printChanges 메서드를 호출해서 SwiftUI 가 View 의 body 를 요청한 이유를 설명해 주고 있습니다. (디버깅 전용이라 아쉽네요...)

여기서는 scaleToFill 값이 변경되어서 View 의 body 가 SwiftUI 에 의해 요청이 되었다는 것으로 해석할 수 있겠네요!

우리는 이렇게 printChanges 를 사용하여 View 에 추가적인 종속성이 있는지 여부를 이해할 수 있습니다.

이번엔 llDB 가 아닌 View 내에서 선언을 해볼까요?

이렇게 앱이 실행하고 디버깅 중인 상태에서 View 에 추가적인 종속성이 있는지 확인을 하고 싶다면 다음과 같이 View 의 본문에 접근할때마다 print 하도록 printChanges 를 호출할 수 있습니다.

하지만 중요한 점은 디버깅 전용이기 때문에 런타임 성능에 영향을 미치게됩니다... 즉, 릴리즈 할때는 꼭 제거를 해줘야 한다는점!

앱을 다시 실행해서 Rocky 의 좋아하는 간식을 비스킷에서 오이로 변경하게 되니 다음과 같은 결과가 나왔습니다.

로그를 보니 self 가 변경되었다 라고 나와있는데 이것은 View 의 값이 변경되었다는 것을 의미합니다.

즉, Scalable Image View 는 간식에 어떠한 종속성이 있는 것으로 보입니다.


⬇️ 어떻게 줄일 수 있는건데?

이제 코드에 집중해보겠습니다.

View 에는 scaleToFilldog 프로퍼티가 존재합니다.
scaleToFill 은 SwiftUI 동적 프로퍼티이며 변경되었다면 로그에 나타났을 겁니다.

로그에 보이지 않았다는 것은 결과적으로 @Self 는 dog 값이 바뀌었다는 의미입니다!

하지만 ScalableDogImage View 는 dog 라는 값 보다 Image 에 관심이 있는 View 입니다.

따라서 우리는 Image 에 관련 없는 dog 라는 값에 대한 의존성을 제거하여 코드를 변경하였고 이렇게 다시 앱을 동작하게 되면 로그가 표시되지 않게됩니다.

당연히 printChanges 에 대한 호출을 지우는 것도 잊지 마세요!

자 우리는 자식 View 인 ScalableDogImage 에 대해 종속성을 제거했으니 부모 View 에 대한 코드도 바꿔야겠죠?

ScalableDogImage 에서 dog 프로퍼티를 없애고 image 프로퍼티로 바꾸었으니 ScalableDogImage 의 이니셜라이저의 값도 image 로 바뀌여야합니다.

ScalableDogImage(dog) -> ScalableDogImage(dog.image)

ScalabelDogImage 를 추출함으로써 필요한 의존성만 남기게 되었는데 Header 에 대해서도 동일한 방법으로 그 자체 View 로 만들 수 있습니다!

다음과 같이 2개의 Text 를 DogHeader 라는 View 로 만들고 dog 라는 프로퍼티에 의존성을 낮출 수 있게 되었죠!

이렇게 코드를 바꾸면서 우리는 더 읽기 쉬워졌습니다. 하지만 작은 View 에 대해서 효과적이라도 매우 큰 구조체에 대해서는 신중해야한다고 합니다.


📌 정리하자면!

우리는 의존성을 줄여나가는 방법을 알아보았습니다. 다시 정리하자면!

  • App 에서 데이터가 변경될 때 업데이트 횟수를 줄이면 성능이 향상됩니다.
  • 그 중 한가지 방법은 의존성을 줄이는 것입니다.
  • View 값을 실제로 의존하는 데이터만 남기도록 줄이는 것을 시도해보아야 합니다.
  • 새로운 Observable Protocol 은 읽기만 하는 의존성으로 자동으로 제한하여 의존성 범위를 조절하는데 도움이 될 수도 있습니다.

아주 간단한 방법이지만 각 View 에 사용할 프로퍼티를 알맞게 사용해서 의존성을 줄여나가는 코드가 이렇게 중요한 것인지에 대해서 알 수 있는 시간이였고 다음 주제인 더 빠른 업데이트에 대해 알아보겠습니다!

긴 글 읽어주셔서 감사하고 피드백은 환영입니다!

profile
📱iOS Developer, 🍎 Apple Developer Academy @ POSTECH 1st, 💻 DO SOPT 33th iOS Part

1개의 댓글

comment-user-thumbnail
2023년 12월 3일

그림과 함께 설명해주셔서 이해하기 쉬웠던 거 같아요 🔥 좋은 글 감사합니다!

답글 달기

관련 채용 정보