LazyVStack사용하기

윤지하·2025년 9월 10일
0

swift

목록 보기
9/9

SwiftUI에서 수직 레이아웃을 구성할 때 VStackLazyVStack 중 어떤 것을 선택해야 할지 고민해본 적 있나요? 최근 개인정보처리방침 화면을 구현하면서 스크롤 감지 기능이 예상과 다르게 동작하는 문제를 겪었는데, 이를 통해 두 컴포넌트의 중요한 차이점을 발견했습니다.

🔍 문제 상황

개인정보처리방침을 끝까지 읽어야만 동의 버튼이 활성화되도록 구현하려고 했습니다. 스크롤 맨 아래에 투명한 뷰를 두고 onAppear로 감지하는 방식을 사용했죠.

VStack(alignment: .leading, spacing: 20) {
    privacyPolicyContent
    
    // 스크롤 끝 감지용
    Color.clear
        .frame(height: 1)
        .onAppear {
            hasScrolledToBottom = true  // 버튼 활성화
        }
}

결과: 화면이 로드되자마자 버튼이 활성화됨...

🧐 원인 분석: VStack의 동작 방식

VStack의 특징

VStack {
    Text("첫 번째")     // ✅ 즉시 생성 및 렌더링
    Text("두 번째")     // ✅ 즉시 생성 및 렌더링  
    Text("세 번째")     // ✅ 즉시 생성 및 렌더링
    // ... 100개여도 모두 즉시 생성
}
  • 즉시 로딩: 모든 자식 뷰를 한 번에 생성
  • 메모리 선점유: 화면에 보이지 않아도 메모리에 로드
  • onAppear 즉시 실행: 뷰가 생성되면서 바로 onAppear 트리거

내 코드에서 일어난 일

  1. VStack 생성
  2. privacyPolicyContent + Color.clear 모두 즉시 메모리에 로드
  3. Color.clearonAppear 바로 실행 → hasScrolledToBottom = true
  4. 사용자가 스크롤하기도 전에 버튼 활성화 🤦‍

💡 해결책: LazyVStack 사용

LazyVStack의 특징

LazyVStack {
    Text("첫 번째")     // ✅ 화면에 보이므로 즉시 생성
    Text("두 번째")     // ⏳ 스크롤해서 보일 때 생성
    Text("세 번째")     // ⏳ 스크롤해서 보일 때 생성
    // ... 필요할 때만 생성
}
  • 게으른 로딩(Lazy Loading): 화면에 나타날 때만 뷰 생성
  • 메모리 효율성: 보이지 않는 뷰는 메모리에 없음
  • 실제 등장 시 onAppear: 진짜로 화면에 나타날 때 트리거

수정된 코드

LazyVStack(alignment: .leading, spacing: 20) {
    privacyPolicyContent
    
    Color.clear
        .frame(height: 1)
        .onAppear {
            withAnimation(.spring()) {
                hasScrolledToBottom = true  // 실제 스크롤했을 때만 실행!
            }
        }
}

결과: 사용자가 정말로 끝까지 스크롤했을 때만 버튼 활성화 ✅

🎯 언제 무엇을 사용할까?

VStack을 사용하는 경우

// ✅ 적은 수의 뷰 (10개 이하)
VStack {
    Text("제목")
    Image("logo")
    Button("시작하기") { }
}

// ✅ 모든 뷰가 화면에 보여야 하는 경우
VStack {
    HeaderView()
    ContentView()
    FooterView()
}

LazyVStack을 사용하는 경우

// ✅ 많은 수의 뷰 (리스트, 피드)
LazyVStack {
    ForEach(posts, id: \.id) { post in
        PostView(post: post)  // 스크롤할 때만 로드
    }
}

// ✅ onAppear 타이밍이 중요한 경우
LazyVStack {
    ContentView()
    TriggerView()  // 실제 보일 때만 트리거
        .onAppear { trackScrollReached() }
}

// ✅ 메모리 최적화가 필요한 경우
LazyVStack {
    ForEach(0..<1000) { i in
        HeavyContentView(index: i)  // 필요할 때만 생성
    }
}

🚨 주의사항

LazyVStack 사용 시 고려사항

  • 애니메이션: 뷰가 나타나면서 생기는 애니메이션 고려 필요
  • 상태 관리: 뷰가 사라지면 상태도 초기화될 수 있음
  • 성능: 매우 적은 뷰에서는 오히려 오버헤드일 수 있음

VStack 사용 시 고려사항

  • 메모리: 많은 뷰에서는 메모리 사용량 증가
  • 초기 로딩: 모든 뷰를 한 번에 생성하므로 초기 로딩 시간 증가

🎉 결론

이번 경험을 통해 배운 것:

  1. 단순히 "더 좋다"는 없다: 상황에 맞는 선택이 중요
  2. onAppear의 동작 방식 이해: VStack vs LazyVStack에서 완전히 다름
  3. 성능 최적화: 적절한 컴포넌트 선택으로 UX 개선 가능

특히 스크롤 감지, 무한 스크롤, 페이지네이션 같은 기능을 구현할 때는 LazyVStack의 게으른 로딩 특성을 잘 활용하면 더 정확하고 효율적인 구현이 가능할 것 같습니다.

profile
성장하고 싶은 개발자

0개의 댓글