英文:
SwiftUI: update a specific object value in a @State array and see changes on screen
问题
我在Swift中还是相对新手,似乎无法在屏幕上更新值(点数)。ScenarioToken是一个CoreData实体。我尝试了一些方法,但似乎卡住了。在我的视图中,我有一个变量:
@State private var scenarioTokens: [ScenarioToken]
我显示所有的元素:
ForEach($scenarioTokens) { $scenarioToken in
HStack {
if let $token = scenarioToken.token {
Text("\($token.label ?? "")")
Spacer()
Button {
increasePoints(scenarioToken: scenarioToken)
} label: {
Image(systemName: "plus.square")
}
.frame(width: 25)
.buttonStyle(BorderlessButtonStyle())
Text("\(scenarioToken.points)")
.frame(width: 25, alignment: .trailing)
Button {
decreasePoints(scenarioToken: scenarioToken)
} label: {
Image(systemName: "minus.square")
}
.buttonStyle(BorderlessButtonStyle())
.frame(width: 25)
}
}
}
我调用的两个函数是:
func increasePoints(scenarioToken: ScenarioToken) {
guard let sign = scenarioToken.token?.sign else {
return
}
scenarioToken.points += 1
}
func decreasePoints(scenarioToken: ScenarioToken) {
guard let sign = scenarioToken.token?.sign else {
return
}
scenarioToken.points -= 1
}
我在Bindable SwiftUI list elements上找到了一篇文章,似乎表明我可以遍历一个状态对象。还有一篇关于Hacking With Swift的帖子,但更多是关于使用@Binding在视图中查看数组中的信息。
如果我将这一行从:
Text("\(scenarioToken.points)")
改为:
Text("\($scenarioToken.points)")
我会得到这个错误:
在实例方法'appendInterpolation'中没有找到精确的匹配项
我正在尝试构建一个[ScenarioToken]数组,它是Scenario和Token之间的多对多关系,还有一个额外的points属性。我希望用户能够添加/编辑完整的Scenario详细视图,添加Token并应用点数,并允许他们在不破坏Core Data中的数据的情况下取消或保存/更新所有更改。
我研究了这个主题,并发现了与此类似的多对多连接(带有额外属性)的内容很少。我试图保持这个问题的范围简明,专注于我在实现中遇到的具体问题,即更新点数。
我看过的所有视频:
- Swift Arcade 基础101,没有更新屏幕,使用警报,不是多对多。
- Sam Meech-Ward 很好的视频,但没有编辑屏幕,是一对多。
- Stewart Lynch 这是Stewart的一个非常好的系列,非常接近回答我的问题,但没有包括多对多。
- Paul Hudson 总是有很好的示例,但不是多对多,也没有评论的编辑/更新。
- CodeWithChris 另一个很好的示例,但不是多对多,也没有一次性保存/存储完整的项目列表。
- Swiftful Thinking 再次,内容很棒,但只是展示了Core Data中一对多关系的工作方式,而不是在应用或更复杂的情况下的多对多。
英文:
I'm still fairly new at Swift and I cannot seem to get the value (points) to update on the screen. ScenarioToken is a CoreData entity.
I have tried a few things but seem to be stuck. I have a variable in my view:
@State private var scenarioTokens: [ScenarioToken]
and I display all the elements:
ForEach ($scenarioTokens) {$scenarioToken in
HStack {
if let $token = scenarioToken.token {
Text("\($token.label ?? "")")
Spacer()
Button{
increasePoints(scenarioToken: scenarioToken)
} label: {
Image(systemName: "plus.square")
}
.frame(width: 25)
.buttonStyle(BorderlessButtonStyle())
Text("\(scenarioToken.points)")
.frame(width: 25, alignment: .trailing)
Button{
decreasePoints(scenarioToken: scenarioToken)
} label: {
Image(systemName: "minus.square")
}
.buttonStyle(BorderlessButtonStyle())
.frame(width: 25)
}
}
}
The two functions I am calling are:
func increasePoints(scenarioToken: ScenarioToken) {
guard let sign = scenarioToken.token?.sign else {
return
}
scenarioToken.points+=1
}
func decreasePoints(scenarioToken: ScenarioToken) {
guard let sign = scenarioToken.token?.sign else {
return
}
scenarioToken.points-=1
}
I an article on Bindable SwiftUI list elements which seemed to indicate I could iterate over a state object. There was another post on Hacking With Swift, but it was more about viewing the information in an array in a view using @Binding.
If I change the line from:
Text("\(scenarioToken.points)")
to:
Text("\($scenarioToken.points)")
I get this error:
> No exact matches in call to instance method 'appendInterpolation'
I am trying to build an array of [ScenarioToken], which is a many to many between Scenario and Token with an additional points attribute. I want the user to be able to add/edit a complete Scenario detail view, adding Tokens and applying points, and allow them to cancel without disrupting the data in Core Data, or save/update with all the changes.
I did research this topic and found little on many to many joins like this (with additional attributes). I tried to keep the scope concise for this question to the specific problem I was having in implementing it, which is down to the updating of the points.
All the videos I've seen:
- Swift Arcade basic 101 w/no update screens, uses alerts, is not many to many.
- Sam Meech-Ward good video but no edit screen and is one to many
- Stewart Lynch this is a really good series by Stewart and comes really close to answering my question, but does not include a many to many
- Paul Hudson great examples always, but not many to many and there is no edit/update of the review.
- CodeWithChris another good example but not many to many or saving/storing a complete list of items all at once.
- Swiftful Thinking again, great content, but shows how one to many relationships work in Core Data but not really in the context of an app or many/many with more complex scenarios.
答案1
得分: 0
我找到了问题。当你有多对多的关系并尝试编辑关系上的属性时,实际上是一个嵌套的可观察对象,这不会触发视图中的信息更改。这在这篇文章中有详细说明:SwiftUI中的嵌套可观察对象。
我已经尝试过创建一个单独的对象来保存关系信息,但它也有相同的问题。但是,我按照文章建议创建了一个子视图,数据更改就变得可见了。
英文:
I found the problem. When you have many:many relationships and are trying to edit an attribute on the relationship, it's actually a nested observable object, which does not trigger the information in the view to change. It was outlined in this post Nested Observable Objects in SwiftUI.
I had already gone down the road of creating a separate object for holding the relationship information, which had the same problem, but I created a subview for it as the article recommended, and the data changes were visible.
答案2
得分: -1
如果您想使用模型更改来更新UI,那么您必须使用ObservableObject
模型和相应的ObservedObject
变量。
ObservableObject
模型:
class ScenarioToeknList: ObservableObject {
static let shared = ScenarioToeknList()
@Published var scenarioTokens = [ScenarioToken]()
}
在您的视图中,像这样创建ObservedObject
:
@ObservedObject var objScenarioTokens: ScenarioToeknList = ScenarioToeknList.shared
现在可以使用ObservedObject
变量来访问令牌数组,以便您可以根据模型的更改来更新视图。
英文:
If you want to update UI with your Model changes then you have to use ObservableObject
model and ObserverdObject
variable for the same.
ObservableObject
Model:
class ScenarioToeknList : ObservableObject{
static let shared = ScenarioToeknList()
@Published var scenarioTokens = [ScenarioToken]()
}
In your view make ObservedObject
like this:
@ObservedObject var objScenarioTokens : ScenarioToeknList = ScenarioToeknList.shared
Now access the array of token using ObservedObject
variable so you can update your view with model changes.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论