ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • SwiftUI에서 UUID를 활용한 뷰 갱신 업데이트
    SwiftUI 2025. 1. 9. 18:53

    안녕하세요. 그린입니다 🍏

    이번 포스팅에서는 SwiftUI에서 실제 많이 사용될 수 있는 UUID를 활용한 뷰 갱신 업데이트에 대해 알아보겠습니다 🙋🏻

     


    무엇을 해보는걸까?

    SwiftUI로 만약 애니메이션을 구현하거나 할 때 가장 까다로울 수 있는 부분이 상태 변경 시 애니메이션을 새로 시작하는것이죠.

    특히, Lottie와 같은 서드파티 애니메이션 라이브러리를 사용할 때 이러한 문제가 더욱 두드러질 수 있습니다.

    그래서 이번에 UUID를 활용하여 해결해보고자 합니다.

     


    문제 상황

    우선 간단한 로티를 사용한 코드를 볼께요.

     

    import Lottie
    import SwiftUI
    
    // 첫 번째 화면
    struct FirstView: View {
      @State var isGrowUp: Bool = false
      var actionBtnText: String {
        isGrowUp ? "rejuvenate" : "Grow Up"
      }
      
      var body: some View {
        NavigationView {
          VStack {
            Text("Here is FirstView")
              .font(.title)
              .padding()
            
            Spacer()
            
            if isGrowUp {
              LottieView(animation: "student")
                .frame(width: 200, height: 200)
            } else {
              LottieView(animation: "baby")
                .frame(width: 200, height: 200)
            }
            
            Button(
              action: {
                isGrowUp.toggle()
              },
              label: {
                Text(actionBtnText)
              }
            )
            
            Spacer()
            
            NavigationLink(destination: SecondView()) {
              Text("Move to the SecondView")
                .padding()
                .background(Color.blue)
                .foregroundColor(.white)
                .cornerRadius(10)
            }
          }
          .onAppear {
            lottieID = UUID()
          }
          .navigationTitle("FirstView")
        }
      }
    }
    
    // 두 번째 화면
    struct SecondView: View {
      var body: some View {
        VStack {
          Text("SecondView")
            .font(.title)
            .padding()
        }
      }
    }

     

    설명해보자면 우선 화면은 두개입니다.

    첫번째 화면에서는 isGrowUp 상태 변수에 따라 아기 혹은 학생의 애니메이션 로티 파일을 한번만 재생해줍니다.

    그리고 두번째 화면으로 이동하는 버튼도 있습니다.

     

    아..! 여기서 Lottie 관련해서는 SwiftUI로 컨버팅해서 만든건데, 이 부분도 아래 코드를 보셔도 좋고 좀 더 로티에 대해 다룬 포스팅을 보셔도 좋습니다 😃

     

     

    Lottie

    안녕하세요. 그린입니다🟢 이번 포스팅에서는 Lottie라는 라이브러리를 알아보려합니다🧐 애니메이션은 항상 어려운데... 정말 어려운데🙃 기본적으로 애플에서 제공해주는 API들로만 하기에

    green1229.tistory.com

     

    struct LottieView: UIViewRepresentable {
      private let animation: String
      
      init(
        animation: String
      ) {
        self.animation = animation
      }
      
      func makeUIView(context: UIViewRepresentableContext<LottieView>) -> UIView {
        let view = UIView(frame: .zero)
        let animationView = LottieAnimationView()
        
        animationView.animation = LottieAnimation.named(animation)
        animationView.frame = view.bounds
        
        animationView.contentMode = .scaleAspectFit
        animationView.loopMode = .playOnce
        animationView.animationSpeed = 0.5
        view.addSubview(animationView)
        
        animationView.play()
        
        NSLayoutConstraint.activate([
          animationView.widthAnchor.constraint(equalTo: view.widthAnchor),
          animationView.heightAnchor.constraint(equalTo: view.heightAnchor)
        ])
        animationView.translatesAutoresizingMaskIntoConstraints = false
        
        return view
      }
      
      func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<LottieView>) {
      }
    }

     

    중요한 부분이 아니니 넘어가겠습니다.

     

    핵심은 상태 변수가 변경되지 않았을 시에도 뷰 갱신 업데이트를 하는 부분이라 좀 더 보기 수월하게 로티를 이용했을뿐 어떤 뷰여도 상관 없습니다.

     

    위 코드를 실행해볼까요?

     

     

    여기서 첫번째 화면에서 아기의 끄덕끄덕 애니메이션이 1회 동작하고 멈추죠.

    그런 다음 다른 화면으로 이동하였다가 돌아왔을때 isGrowUp 상태 변수가 변경된게 없으니 그대로 유지되어 애니메이션이 다시 시작되지 않아요.

    왜냐하면, SwiftUI가 기존 뷰를 재사용하고 있기 때문입니다.

     

    근데 만약 요구사항이 해당 뷰가 onAppear될때 1회 애니메이션 노출을 시켜야한다면?

    이때부터는 선택지가 있습니다.

    하나는 해당 FirstView가 disAppear될 때 현재 상태 정보를 저장하고 임시로 갈아끼워주고 다시 onAppear가 될 때 임시 상태 정보에서 다시 불러와 상태 값을 변경해 동작하도록도 할 수 있죠.

     

    그런데, 이런 방식은 오히려 오버엔지니어링을 야기할 수 있습니다 😱

     

    그래서, 가장 확실하고 리스크가 없는 방법으로 UUID를 활용해 해결해볼 수 있어요.

     


    UUID를 활용하여 해결하기

    UUID는 고유한 식별자를 생성하는데, 이를 뷰의 id로 사용하면 SwiftUI에게 완전히 새로운 뷰를 생성하도록 시킬 수 있습니다.

     

    코드로 볼까요?

     

    struct FirstView: View {
      @State var isGrowUp: Bool = false
      var actionBtnText: String {
        isGrowUp ? "rejuvenate" : "Grow Up"
      }
      🙋🏻🙋🏻🙋🏻🙋🏻🙋🏻🙋🏻
      @State private var lottieID = UUID()
      
      var body: some View {
        NavigationView {
          VStack {
            Text("Here is FirstView")
              .font(.title)
              .padding()
            
            Spacer()
            
            if isGrowUp {
              LottieView(animation: "student")
                .frame(width: 200, height: 200)
                  🙋🏻🙋🏻🙋🏻🙋🏻🙋🏻🙋🏻
                .id(lottieID)
            } else {
              LottieView(animation: "baby")
                .frame(width: 200, height: 200)
                  🙋🏻🙋🏻🙋🏻🙋🏻🙋🏻🙋🏻
                .id(lottieID)
            }
            
            Button(
              action: {
                isGrowUp.toggle()
              },
              label: {
                Text(actionBtnText)
              }
            )
            
            Spacer()
            
            NavigationLink(destination: SecondView()) {
              Text("Move to the SecondView")
                .padding()
                .background(Color.blue)
                .foregroundColor(.white)
                .cornerRadius(10)
            }
          }
          .onAppear {
            🙋🏻🙋🏻🙋🏻🙋🏻🙋🏻🙋🏻
            lottieID = UUID()
          }
          .navigationTitle("FirstView")
        }
      }
    }

     

    이모지로 표시된곳들만 보면 됩니다.

    고유 식별자를 상태 변수로 선언합니다.

    즉, 뷰가 처음 생성될 때 초기화되죠.

     

    그리고 각 로티 뷰에 id 수정자를 적용해줍니다.

    그럼 우리는 이제 해당 뷰를 갱신 리프레쉬 시켜주고 싶을때 lottieID = UUID()를 호출해서 새로운 UUID를 생성해줘서 갱신할 수 있습니다.

     

    그럼 돌려볼까요?

     

     

    1회 애니메이션이 끝난 후 다른 뷰로 갔다 다시 되돌아오면 뷰가 다시 갱신되어 애니메이션이 실행되죠?

    이런 차이가 있어요!

     

    근데 여기서 UUID가 아닌 다른 타입을 사용하면 안되는걸까요?

     

    물론 됩니다! 그런데, UUID를 사용하는 이점이 있습니다 😃

     


    UUID를 사용하는 이유

    1️⃣ 유니크성 보장

    UUID는 실질적으로 중복될 가능성이 없는 고유한 값을 제공해주기에 유니크성이 보장됩니다.

    2️⃣ 간단한 구현

    Bool이나 Int 값을 토글하고 바꾸는것보다 훨씬 더 안정적인 방식으로 뷰를 리프레시 할 수 있습니다.

    3️⃣ 메모리 효율성

    UUID는 상대적으로 가벼운 값 타입이고 뷰가 사라질 때 자동으로 메모리에서 해제됩니다.

    String 같은 컬렉션 타입들이 적절하지 않을 수 있는 이유이기도 합니다.

     

    그런데 이렇게 편리하게 구현할 수 있지만 주의할 점도 있어요!

     


    주의할 부분

    과도하게 UUID 변경을 사용하면 뷰를 완전히 새롭게 그려버리는것이기에 필요한 경우에만 사용해야 합니다.

    또한, 복잡한 뷰 계층 구조에서는 ID 변경이 성능에 영향을 미칠 수 있기에 꼭 필요하다고 판단되는 컴포넌트에서만 적용하는것이 좋습니다.

     


    마무리

    UUID를 활용한 뷰 갱신 업데이트 방식은 SwiftUI에서 자주 발생하는 애니메이션 재생 문제를 깔끔하게 해결할 수 있는 방법 중 하나입니다.

    특히 Lottie와 같은 서드파티 애니메이션을 다룰때 유용하고 간단하며 효과적이기도 하죠!

    해당 방식을 통해서 더 나은 사용자 경험과 요구사항을 지킬 수 있을거라 생각됩니다 👍

    특히, SwiftUI의 선언적 특성을 해치지 않으면서 원하는 동작을 구현할 수 있죠.

Designed by Tistory.