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.
- Creating a CardModel (file 1):
struct CardModel: Hashable, Codable, Identifiable {
let id: Int
let topic: String
let category: String
var saved: Bool
}
- Retrieving data from json and creating an array of structs (file 2):
var cardsModelArray: [CardModel] = load("LetsTalkTopics.json")
- Func to pickup random item from the array (file 3):
func pickRandomCard() -> CardModel {
let randomCard = cardsModelArray.randomElement()!
return randomCard
}
- 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)
}
- 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()
}
}
}
}
}