SwiftUI:在 @State 数组中更新特定对象的值,并在屏幕上查看更改。

huangapple go评论65阅读模式
英文:

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.

huangapple
  • 本文由 发表于 2023年6月26日 21:00:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/76556940.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定