Hi,
I programmed an app to draw cards from a deck. After a card is drawn it is hidden from the deck. The drawn state is a property of a card struct in an array inside a deck struct. This worked well in the past since iOS 14. Since Xcode 16 this does not work as before anymore.
This is the Card
struct with a Bool
for the drawn state:
struct Card: Codable, Identifiable, Equatable, Hashable {
var isDrawn: Bool
…
}
The cards are stored in an array that is inside a CardDeck
struct among other properties:
struct CardDeck: Codable {
var cards: [Card] = []
var cardSpacing: CGFloat
…
mutating func hideCard(card: Card) {
if let cardIndex = self.cards.firstIndex(of: card) {
self.cards[cardIndex].isDrawn = true
}
}
}
The deck is a published property of an observable DeckStore
class for permanent storage:
class CardDeckStore: ObservableObject {
@Published var deck: CardDeck = CardDeck()
…
}
The DeckStore
class is @StateObject
in the App struct:
@main
struct CardApp: App {
@StateObject var store = OpaliaCardDeckStore()
var body: some Scene {
WindowGroup {
ContentView(deck: $store.deck)
}
}
}
Here is the simplified DrawCardsView
where I present and draw the cards:
struct DrawCardsView: View {
@Binding var deck: CardDeck
var body: some View {
// Was a NavigationView before
NavigationStack() {
HStack(spacing: deck.cardSpacing) {
ForEach($deck.cards) { $card in
if card.isDrawn {
CardBackView(card: card)
.hidden()
}
else {
NavigationLink(destination: DrawnCardView(card: card, deck: $deck)) {
CardBackView(card: card)
}
}
}
}
}
}
}
To hide a drawn card, hideCard()
is called in the DrawnCardView:
struct DrawnCardView: View {
var card: Card
@Binding var deck: CardDeck
@State var drawnCard: DrawnCard = .init()
var body: some View {
DrawnCardSimpleView(drawnCard: self.drawnCard)
.onDisappear(perform: {
deck.hideCard(card: self.card)
})
}
}
I am not a pro in programming and there are better solutions to program this, but this worked until I upgraded to Xcode 16. Now it seems the isDrawn
state of a card does not update the DrawCardsView
right away anymore. A drawn card is not hidden and still present when returning to DrawCardsView
from DrawnCardView
. After tapping the same card again or another update of the UI, the card will then be hidden.
I do not know the reason. It seems the binding of the isDrawn
state inside an element of the card array in the observable object is not working anymore. Other properties of the observable object like cardSpacing
do work as expected.
I can empty the cards array and fill it with new cards without problems in the DrawCardsView.
I eliminated the ForEach
loop by addressing the array elements directly, but to no avail. I tried different solutions I found on the internet, but nothing worked.
I was under the impression that every change in an observable object would update the UI.
Any ideas for a explanation/solution?
Thanks,
Christian