I have some code that I am using, the idea is that the user selects a card they like and a sheet is presented to show more information about that card. The problem is, if I don't have the Text(selectedCard?.name ?? "Not selected")
line, it crashes. I was just wondering what I don't understand about Swift/SwiftUI that is making this happen and how I could fix it (as I don't want it to say what card they have selected).
It is where the sheet comes to be presented that it crashes as it finds a nil
value for selectedCard
but selectedCard
should not be nil when that runs. If I add the seemingly unrelated line to display which card has been selected, the value is set fine and it does not crash.
Full code:
import SwiftUI
struct CardsView: View {
@State private var cardlist = [Cards]()
@State private var showingSheet = false
@State private var selectedCard: Cards?
let columns = [
GridItem(.adaptive(minimum: 120))
]
var body: some View {
NavigationView() {
ScrollView (.vertical, showsIndicators: false) {
Text("View our full collection of cards below:")
.padding(.leading, 20)
.frame(maxWidth: .infinity, alignment: .leading)
Text(selectedCard?.name ?? "Not selected") // This line stops it from crashing
LazyVGrid(columns: columns, spacing: 10) {
ForEach(cardlist, id: \.name) { thecard in
CardItem(card: thecard)
.onTapGesture {
selectedCard = thecard
showingSheet.toggle()
}
}
}
.padding([.leading, .trailing])
Spacer()
}
.navigationTitle("Cards")
}
.sheet(isPresented: $showingSheet) {
SpecificCardView(card: selectedCard!)
}
.onAppear() {
loadCards()
}
}
func loadCards() {
...
}
}
CodePudding user response:
Your problem is likely due to the view diffing algorithm having a different outcome if you have the text value present, since that would be a difference in the root view. Since you have two pieces of state that represent the sheet, and you are force unwrapping one of them, you're leaving yourself open to danger.
You should get rid of showingSheet
, then use the item binding of sheet instead. Make Cards
conform to Identifiable
, then rewrite the sheet modifier as:
.sheet(item: $selectedCard) { SpecificCardView(card: $0) }
This will also reset your selected card to nil when the sheet is dismissed.