Attempt to present * on * from * while a presentation is in progress

Hi I'm new to Swiftui. I want to show a sheet and pass a var to it. In the case below when I tap on a list view it will popup then disappear. But subsequent taps will work as intended. Main view:

struct ContentView: View {
    
    @State private var selectedMonth = 1
    @State private var selectedYear = "2024"
    let months = [1,2,3,4,5,6,7,8,9,10,11,12]
    @State private var isShowing = false
    
    var body: some View {
        
        List {
            ForEach (months, id: \.self) { month in
                HStack {
                    ViewList(month: month, year: selectedYear)
                }
                .onTapGesture {
                    isShowing = true
                    selectedMonth = month
                }
                .sheet(isPresented: $isShowing){
                    PopupView(month: selectedMonth, year: selectedYear)
                .presentationDetents([.large])
                }
            }
        }
        .listRowSpacing(2)
        .listStyle(.grouped)
    }
}

ViewList:

struct ViewList: View {
    
    var month: Int
    var year: String
    @State private var selectedMonthText = "Jan"
    
    var body: some View {
        
        VStack (alignment: .leading) {
            Text(selectedMonthText + " / " + year)
                .font(.headline)
        }
        .onAppear {
            switch month {
            case 01:
                selectedMonthText = "Jan"
            case 02:
                selectedMonthText = "Feb"
            case 03:
                selectedMonthText = "Mar"
            case 04:
                selectedMonthText = "Apr"
            case 05:
                selectedMonthText = "May"
            case 06:
                selectedMonthText = "Jun"
            case 07:
                selectedMonthText = "Jul"
            case 08:
                selectedMonthText = "Aug"
            case 09:
                selectedMonthText = "Sep"
            case 10:
                selectedMonthText = "Oct"
            case 11:
                selectedMonthText = "Nov"
            case 12:
                selectedMonthText = "Dec"
            default:
                selectedMonthText = "All"
            }
        }
    }
}

Then my popup:

struct PopupView: View {
    
    @Environment(\.dismiss) var dismiss
    var month: Int
    var year: String
    @State private var selectedMonthText = "Jan"
    @State private var imageText = "plus"
    @State private var items = ["Cat", "Dog", "Bird", "Snake"]
    
    
    var body: some View {
        
        Button("Dismiss"){
            dismiss()
        }
        Text(selectedMonthText + " / " + year)
        List {
            ForEach(items, id: \.self) {item in
                HStack {
                    Text(item)
                    Text("Fed on: ")
                    Text(selectedMonthText)
                }
            }
        }
        .listRowSpacing(0)
        .listStyle(.inset)
        .onAppear {
            switch month {
            case 01:
                selectedMonthText = "Jan"
            case 02:
                selectedMonthText = "Feb"
            case 03:
                selectedMonthText = "Mar"
            case 04:
                selectedMonthText = "Apr"
            case 05:
                selectedMonthText = "May"
            case 06:
                selectedMonthText = "Jun"
            case 07:
                selectedMonthText = "Jul"
            case 08:
                selectedMonthText = "Aug"
            case 09:
                selectedMonthText = "Sep"
            case 10:
                selectedMonthText = "Oct"
            case 11:
                selectedMonthText = "Nov"
            case 12:
                selectedMonthText = "Dec"
            default:
                selectedMonthText = "All"
            }
        }
    }
    
}

Answered by jacobsdesigns in 794335022

Thank you.

A few things here:

You don't need to write this: let months = [1,2,3,4,5,6,7,8,9,10,11,12]

You can use: let months = [1...12]

But, you only use this once, so instead of this: ForEach (months, id: \.self) { month in you can use this: ForEach(1...12, id: \.self) { month in


Secondly, when you write

switch month {
    case 01:
...

You've declared month as an Int, and you don't need to use leading zeroes, so you should write:

switch month {
    case 1:
...

BUT... There's a much simpler way of doing this. Look into DateFormatter() with a format of MMM. Something like:

func getMonthText(_ month: Int) -> String {
	let dateFormatter = DateFormatter()
	dateFormatter.locale = Locale(identifier: "en_US")
	dateFormatter.dateFormat = "MM"
	let firstOfMonth = dateFormatter.date(from: "\(month)")!
	dateFormatter.dateFormat = "MMM"
	return dateFormatter.string(from: firstOfMonth)
}

The issue you're having with presenting is because you've put the sheet inside the ForEach loop. You're only showing the sheet once when one thing is tapped, so you can just add it anywhere in the View. This works:

import SwiftUI

struct ContentView: View {
	@State private var selectedMonth = 1
	@State private var selectedYear = "2024"
	@State private var isShowing = false

	var body: some View {
		List {
			ForEach(1...12, id: \.self) { month in
				HStack {
					ViewList(month: month, year: selectedYear)
						.onTapGesture {
							isShowing = true
							selectedMonth = month
						}
				}
			}
		}
		.listRowSpacing(2)
		.listStyle(.grouped)

    // MOVED THIS TO HERE
		.sheet(isPresented: $isShowing){
			PopupView(month: selectedMonth, year: selectedYear)
				.presentationDetents([.large])
		}
	}
}


struct ViewList: View {
	var month: Int
	var year: String

	var body: some View {
		VStack(alignment: .leading) {
			Text("\(getMonthText(month)) / \(year)")
				.font(.headline)
		}
	}
}


struct PopupView: View {
	@Environment(\.dismiss) var dismiss
	var month: Int
	var year: String
	@State private var selectedMonthText = "Jan"
	@State private var imageText = "plus"
	@State private var items = ["Cat", "Dog", "Bird", "Snake"]

	var body: some View {
		Button("Dismiss") {
			dismiss()
		}
		Text("\(selectedMonthText) / \(year)")
		List {
			ForEach(items, id: \.self) {item in
				HStack {
					Text(item)
					Text("Fed on: ")
					Text(selectedMonthText)
				}
			}
		}
		.listRowSpacing(0)
		.listStyle(.inset)
		.onAppear {
			selectedMonthText = getMonthText(month)
		}
	}
}


func getMonthText(_ month: Int) -> String {
	let dateFormatter = DateFormatter()
	dateFormatter.locale = Locale(identifier: "en_US")
	dateFormatter.dateFormat = "MM"
	let firstOfMonth = dateFormatter.date(from: "\(month)")!
	dateFormatter.dateFormat = "MMM"
	return dateFormatter.string(from: firstOfMonth)
}


#Preview {
    ContentView()
}
Accepted Answer

Thank you.

Attempt to present * on * from * while a presentation is in progress
 
 
Q