swift UI로 모달까지 만들어봄.

BS_Lee·2025년 7월 24일

swift

목록 보기
21/21
post-thumbnail

SwiftUI에서 .sheet가 동작하는 과정 완전 이해하기

SwiftUI로 앱을 만들다 보면, 리스트에서 아이템을 선택하면 상세 화면이 뜨는 패턴을 자주 구현하게 된다.
이번에는 FrameworkGridView, FrameworkGridViewModel, FrameworkDetailView 세 가지를 기준으로 .sheet가 어떻게 동작하는지 하나씩 뜯어보자.


1. 전체 구조 다시 보기

FrameworkGridView

@StateObject var viewModel = FrameworkGridViewModel()

var body: some View {
    NavigationView {
        ScrollView {
            LazyVGrid(columns: columns) {
                ForEach(MockData.frameworks, id: \.id) { framework in
                    FrameworkTitleView(framework: framework)
                        .onTapGesture {
                            viewModel.selectedFramework = framework
                        }
                }
            }
        }
        .navigationTitle("🍎 Frameworks")
        .sheet(isPresented: $viewModel.isShowingDetailView) {
            FrameworkDetailView(
                frameWork: viewModel.selectedFramework!,
                isShowingDetailView: $viewModel.isShowingDetailView
            )
        }
    }
}

FrameworkGridViewModel

final class FrameworkGridViewModel: ObservableObject {
    var selectedFramework: Framework? {
        didSet {
            isShowingDetailView = true
        }
    }
    
    @Published var isShowingDetailView = false
}

FrameworkDetailView

struct FrameworkDetailView: View {
    var frameWork: Framework
    @Binding var isShowingDetailView: Bool
    
    var body: some View {
        VStack {
            HStack {
                Spacer()
                Button {
                    isShowingDetailView = false
                } label: {
                    Image(systemName: "xmark")
                        .foregroundColor(Color(.label))
                        .imageScale(.large)
                        .frame(width: 44, height: 44)
                }
            }
            .padding()
            
            Spacer()
            FrameworkTitleView(framework: frameWork)
            Text(frameWork.description)
                .font(.body)
                .padding()
            Spacer()
            Button {
                // 더 알아보기 로직
            } label: {
                AFButton(title: "더 알아보기")
            }
        }
    }
}

2. 동작 흐름 정의

1) onTapGestureselectedFramework 주입

FrameworkGridView에서 사용자가 특정 아이템을 탭하면
viewModel.selectedFramework에 선택한 framework가 할당된다.

.onTapGesture {
    viewModel.selectedFramework = framework
}

즉, FrameworkGridView이미 생성된 ViewModel 인스턴스를 사용하며,
선택한 데이터를 ViewModel에 넘겨주는 역할만 한다.


2) didSet을 통한 isShowingDetailView 변경

FrameworkGridViewModel의 핵심 로직은 selectedFrameworkdidSet이다.

var selectedFramework: Framework? {
    didSet {
        isShowingDetailView = true
    }
}
  • 선택된 데이터가 할당되면
  • 자동으로 isShowingDetailViewtrue로 바뀐다.

즉, 선택과 동시에 상세 화면을 띄우라는 신호를 보내는 구조다.


3) @Published.sheet의 반응

isShowingDetailView@Published이기 때문에,
값이 변경되면 이 값을 감시하고 있는 View가 즉시 반응한다.

.sheet(isPresented: $viewModel.isShowingDetailView) {
    FrameworkDetailView(
        frameWork: viewModel.selectedFramework!,
        isShowingDetailView: $viewModel.isShowingDetailView
    )
}

즉,

  • isShowingDetailView = true.sheet가 뜬다
  • isShowingDetailView = false.sheet가 닫힌다

FrameworkDetailView 내부에서 xmark 버튼을 눌러 isShowingDetailView = false로 바꾸면,
자동으로 시트가 사라지는 이유도 여기에 있다.


4) 선택된 데이터의 전달

.sheet가 실행될 때, selectedFramework에 저장된 데이터가 그대로 전달된다.

FrameworkDetailView(
    frameWork: viewModel.selectedFramework!,
    isShowingDetailView: $viewModel.isShowingDetailView
)

즉, FrameworkDetailView가 보여줄 데이터는
onTapGesture에서 선택된 그 데이터 그대로다.


3. 흐름 요약

  1. 탭 이벤트 발생selectedFramework에 선택된 데이터가 주입된다.
  2. didSet 실행isShowingDetailViewtrue로 변경된다.
  3. @Published 반응.sheet가 자동으로 뜬다.
  4. 데이터 전달selectedFrameworkFrameworkDetailView에 전달되어 View에 표시된다.
  5. 닫기 버튼 동작isShowingDetailView = false로 변경되어 .sheet가 닫힌다.

4. 한 줄 정리

단계설명
데이터 선택onTapGesture로 ViewModel의 selectedFramework가 갱신된다
상태 변화didSet으로 isShowingDetailViewtrue로 바뀐다
UI 반응@Published가 변화를 감지해 .sheet를 띄운다
데이터 전달.sheet에서 선택된 Framework를 상세 화면에 넘겨준다

즉, View → ViewModel → View의 단방향 흐름으로 동작하며,
상태 변경은 ViewModel이 책임지고, View는 그 상태를 구독하며 UI를 업데이트한다.

마무리로 정리한 내용

0개의 댓글