更改结构模型中的值。
更改结构模型中的值。
我遇到了一个问题,即将结构中的项目添加到收藏夹中。想法如下:
- 我有一个带有卡片数据的json
- 在主屏幕上,应用程序显示一个随机卡片
- 用户可以选择另一张随机卡片或将其保存到收藏夹中。
以下是代码。
- 创建CardModel(文件1):
struct CardModel:Hashable,Codable,Identifiable {
let id:Int
let topic:String
let category:String
var saved:Bool
}
- 从json中检索数据并创建结构数组(文件2):
var cardsModelArray:[CardModel] = load(“LetsTalkTopics.json”)
- 从数组中随机选择项目的功能(文件3):
func pickRandomCard()-> CardModel {
let randomCard = cardsModelArray.randomElement()!
返回randomCard
}
- 更改“saved”布尔值的功能(文件4)
func saveCard(card:CardModel){
let index = card.id
cardsModelArray[index] = CardModel(id:index,topic:card.topic,category:card.category,saved:!card.saved)
}
- 查看文件(文件5,简化)
import SwiftUI
struct StackOverFlow:View {
@State var currentCard = pickRandomCard()
var body:some View {
VStack {
CardViewStackOver(cards:currentCard)
Button(“显示随机卡片”){
currentCard = pickRandomCard()
}
Button(“保存项目”){
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)
}
}
}
}
}
但是我肯定做错了什么,在单独的视图中,我展示了保存的卡片,但它不起作用(显示一些随机卡片,并且一些保存的卡片有重复)。通过我的研究,我发现结构是不可变的,当我尝试编辑一个值时,基本上Swift会创建一个副本并对副本进行更改。如果是这样,创建此收藏功能的正确方法是什么?
问题出现的原因是在结构体模型中更改值的方法不正确,导致无法实时更新布尔值的图标。
解决方法是使用更合适的方法来更改结构体模型中的值,并解决实时更新图标的问题。
以下是一个修复问题的解决方案:
func saveCardMinus(currentCard: CardModel) {
var index = currentCard.id - 1
cardsModelArray[index].saved.toggle()
}
但是,我确信整个解决方案都是不好的。正确/更合适的解决方法是什么?
(顺便说一句,现在我面临另一个问题:布尔值的图标更新不是实时的,您需要再次打开该卡片才能看到新值(填充的心形/未填充的心形))
问题的原因:
问题出现的原因是结构体(struct)中的属性值无法被更改,导致无法更新选中卡片的状态。
解决方法:
为了解决这个问题,可以使用Binding来传递选中的卡片。但是由于存在多个不良实践,我对整个代码进行了重构。
重构后的代码如下:
struct StackOverFlow: View {
@State private var currentCardIndex: Int?
@State private var cards: [CardModel] = []
var body: some View {
VStack {
if let index = currentCardIndex {
CardViewStackOver(card: $cards[index])
}
Button("Show random card") {
currentCardIndex = (0.. }
Button("Save / delete item") {
if let index = currentCardIndex {
cards[index].saved.toggle()
}
}
}
.onAppear {
if cards.isEmpty {
cards = load("LetsTalkTopics.json")
}
}
}
}
struct CardViewStackOver: View {
@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()
}
}
}
}
}
经过重构后,我们使用了`@State`来包装`currentCardIndex`和`cards`属性,使它们具有状态管理的能力。同时,在`CardViewStackOver`结构体中,我们使用了`@Binding`来传递选中的卡片,以便能够更改其状态。
这样,我们就解决了原始代码中无法更改结构体属性值的问题,并且通过重构代码,消除了一些不良实践。