Home > Blockchain >  Change values in struct model
Change values in struct model

Time:09-04

I'm stuck with adding items from struct to favorites. The idea:

  • I have a json with data for cards
  • On the main screen app shows a random card
  • The user could pick another random card or save it to favorites.

Code below.

  1. Creating a CardModel (file 1):
struct CardModel: Hashable, Codable, Identifiable {
    let id: Int
    let topic: String
    let category: String
    var saved: Bool
}
  1. Retrieving data from json and creating an array of structs (file 2):
var cardsModelArray: [CardModel] = load("LetsTalkTopics.json")

  1. Func to pickup random item from the array (file 3):
func pickRandomCard() -> CardModel {
    let randomCard = cardsModelArray.randomElement()!
    return randomCard
}
  1. Func to change the "saved" bool value (file 4)
func saveCard(card: CardModel) {
    let index = card.id
    cardsModelArray[index] = CardModel(id: index, topic: card.topic, category: card.category, saved: !card.saved)
}
  1. View file (file 5, simplified)
import SwiftUI

struct StackOverFlow: View {
    
    @State var currentCard = pickRandomCard()
    
    var body: some View {
        VStack{
            CardViewStackOver(cards: currentCard)
            Button("Show random card") {
                    currentCard = pickRandomCard()
            }
            
            Button("Save item") {
                saveCard(card: currentCard)
            }
    }
}

struct StackOverFlow_Previews: PreviewProvider {
    static var previews: some View {
        NavigationView {
            StackOverFlow()
        }
    }
}


struct CardViewStackOver: View {
    
    let cards: CardModel
    
    var body: some View {
        VStack {
            Text(cards.topic)
            Text(cards.category)
            Text(String(cards.id))
            HStack {
                if cards.saved {
                    Image(systemName: "heart.fill")
                        .font(.title)
                        .padding(15)
                        .padding(.bottom, 20)
                } else {
                    Image(systemName: "heart")
                        .font(.title)
                        .padding(15)
                        .padding(.bottom, 20)
                }
            }
        }
    }
}

But I definitely making something wrong, in a separate view I'm showing saved cards but it doesn't work (it shows some random cards, and some saved cards have duplicates). With my research, I found out that structs are immutable and when I'm trying to edit a value, basically swift creates a copy of it and makes changes in the copy. If so, what would be the right approach to create this favorite feature?

CodePudding user response:

A solution that fixed the problem:

func saveCardMinus(currentCard: CardModel) {
    var index = currentCard.id - 1
    cardsModelArray[index].saved.toggle()
}

But I'm sure that the whole solution is bad. What is the right/more proper way to solve it?

(and btw, now I face another problem: the icon for bool value updates is not in real-time, you need to open this card again to see a new value (filled heart/unfilled heart))

CodePudding user response:

You could use a Binding to pass the selected card on. But I restructured the whole code as there were multiple bad practices involved:

struct StackOverFlow: View {
    //store the current selected index and the collection as state objects
    @State var currentCardIndex: Int?
    @State var cards: [CardModel] = []
    
    var body: some View {
        VStack{
            //if there is an index show the card
            if let index = currentCardIndex{
                CardViewStackOver(card: $cards[index])
            }
            Button("Show random card") {
                // just create a random index
                currentCardIndex = (0..<cards.count).randomElement()
            }
            
            Button("Save / delete item") {
                if let index = currentCardIndex{
                    //you save delete as favorite here
                    cards[index].saved.toggle()
                }
            }
        }.onAppear{
            //don´t exactly know where this function lives
            if cards.count == 0{
               cards = load("LetsTalkTopics.json")
            }
        }
    }
}

struct CardViewStackOver: View {
    //use binding wrapper here
    @Binding var card: CardModel
    
    var body: some View {
        VStack {
            Text(card.topic)
            Text(card.category)
            Text(String(card.id))
            HStack {
                Image(systemName: card.saved ? "heart.fill" : "heart")
                    .font(.title)
                    .padding(15)
                    .padding(.bottom, 20)
                    .onTapGesture {
                        card.saved.toggle()
                    }
            }
        }
    }
}
  • Related