[SwiftUI] sheet에 띄울 값이 반영되지 않고 nil로 나와요

·2025년 4월 24일
0

iOS

목록 보기
5/5
post-thumbnail

상황 설명

MainView 안에 StampView가 존재.
StampView 내 버튼 터치에 따라, 아침 점심 저녁 기타의 습관 목록을 sheet에 가져옴.

기존 구현

  1. StampView에 아침 점심 저녁 기타 버튼이 존재. 이를 누르면 isSheetPresented = true가 되면서 sheet 등장!
  2. 등장한 sheet에 각 시간대별 습관 목록이 떠야 함 -> 안 뜨고 nil로 나옴.
struct MainView: View {

    @State var isPresentSheet = false
    @State var timeSlot: TimeSlot? = nil

    var body: some View {
        VStack {
            if isEditing {
                Text("수정 모드")
                StampView(myHabit: habits.first ?? .stub01, isPresentSheet: $isPresentSheet, timeSlot: $timeSlot, isEditing: true)

            } else {
                Text("인증 모드")
                StampView(myHabit: habits.first ?? .stub01, isPresentSheet: $isPresentSheet, timeSlot: $timeSlot, isEditing: false)

            }
        }
        .sheet(isPresented: self.$isPresentSheet) { // 여기 주목!
            ScrollView {
                VStack {
                    switch timeSlot {
                    case .morning:
                        ForEach(MorningHabitType.allCases, id: \.**self**) { type in

                            Button {

                            } label: {
                                Text(type.description)
                            }

                        }

                    case .afternoon:

                    case .evening:

                    case .extra:

                    case nil:

                        Text("nil")

                    }
                }
            }
        }
    }
}

StampView에 isPresentSheet와 timeSlot를 바인딩해서 넘김.
버튼 누를 때 값 수정... MainView에서 Sheet도 잘 뜨고 .morning도 잘 수정됐는데 왜 nil인가 했더니

    var isEditingView: **some** View {
        VStack(spacing: -40) {
            Button {
                timeSlot = .morning
                isPresentSheet.toggle()
                print("StampView - isEditingView - morning")

            } label: {
            ...
            }
        }
    }

문제의 원인 .sheet(isPresented:)

현재 .sheet(isPresented:)를 쓰고 있는데, isPresented만 체크하고, timeSlot 값이 변했는지 체크는 안 한다.
SwiftUI의 sheet는 isPresented만 보고 sheet를 띄우니까, 버튼 누르자마자 timeSlot이 세팅되는 타이밍보다 sheet 띄우는 타이밍이 살짝 빠를 수 있다...

그래서! timeSlot 세팅 전에 .sheet가 떠버리면서 timeSlot == nil 상태가 된다.

해결 방법 .sheet(item:)

.sheet(item:binding)은 Optional 타입이 바뀔 때 자동으로 열리고, timeSlot에 값이 들어오는 걸 트리거로 sheet가 열린다.

그래서 값 세팅 먼저 → sheet 열기 흐름이 자연스럽게 맞춰짐.

주의할 점!
.sheet(item:) 쓸 때는 timeSlot이 Identifiable이어야 한다.
만약 TimeSlot이 Identifiable 프로토콜 안 따른다면, >간단히 extension 하나 추가하기

**enum** TimeSlot: String, Codable, Identifiable, CaseIterable { // Identifiable 추가하고
    **case** morning
    **case** afternoon
    **case** evening
    **case** extra

}

**extension** TimeSlot {
    **var** id: String { rawValue } //Identifiable를 만족하기 위해선 id 값 필요
}

수정본

      .sheet(item: $timeSlot) { timeSlot **in** // item 사용하기
            ScrollView {
                VStack {
                    **switch** timeSlot {
                    **case** .morning:
                        ForEach(MorningHabitType.allCases, id: \.**self**) { type **in**

                            Button {
                            } label: {
                                Text(type.description)
                            }
                        }

잘 된당 히히

참고자료 : 공식문서

profile
SOOP

0개의 댓글