使用ForEach循环在SwiftUI的Form视图中显示字典项的键和值。

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

Using a ForEach loop to show the key and value of dictionary items in a Form view in SwiftUI

问题

我正在尝试创建一个我认为应该是一个简单的代码片段,以显示字典项的键并在表单视图内的一行中实现Stepper或Picker来修改键的值。

在一天结束时,我所试图实现的只是向用户显示他们输入的单词列表,以及他们可以更改的关联数字值。

几乎每种解决问题的方法都导致了我的画布彻底崩溃,因为显然我的尝试解决这个问题都是错误的。

无论如何,以下是我尝试解决问题的一些示例。请注意,我还尝试了许多类型的视图,比如带有单词的文本和关联整数的选择器。我只是认为,为了演示问题,对于每个示例使用Stepper可能已经足够了。

struct Likenesses {
    let word: String
    var likeness: Int = 0
}

struct ContentView: View {
    
    @State private var words: [String] = []
    @State private var likeness: [Int] = []
    @State private var wordLikeness: [String:Int] = [:]
    @State private var StructLikeness: [Likenesses] = []
    
    var body: some View {
        Form {
            
            // 字典方法
            Section {
                ForEach(Array(wordLikeness.keys), id: \.self) { key in
                    Stepper("\(key)", value: $wordLikeness[key], in: 0...8, step: 1)
                }
            }
            
            // 数组方法
            Section {
                ForEach(0..<words.count, id: \.self) { i in
                    Stepper("\(words[i])", value: $likeness[i], in: 0...8, step: 1)
                }
            }
            
            // 结构体方法
            Section {
                ForEach(StructLikeness, id: \.self) { s in
                    /*
                    是的,我知道结构体不是引用并且会传递副本,这是我以后需要解决的另一个问题,但目前,这可以让你了解我尝试用结构体解决的问题的概念
                    */
                    Stepper("\(s.word)", value: $s.likeness, in: 0...8, step: 1)
                }
            }
        }
    }
}
英文:

I'm trying to create what I thought would be a simple bit of code to show the key of a dictionary item and implement a Stepper or a Picker to modify the key's value in a single line within a Form view.

At the end of the day, all I'm trying to accomplish is showing the user a list of words they've entered, along with an associated number value that they can change.

Almost every method to solution my problem resulted in absolutely blowing up (crashing) my canvas because evidently my attempts at solutioning this are just that wrong.

Anyway, below are some examples of ways I've been trying to solve my problem. Note that I've also tried many types of views, like Text with the word, and a picker for the associated Integer. I just figure for the sake of demonstrating the problem, using a Stepper for each example might be good enough.

struct Likenesses {
    let word: String
    var likeness: Int = 0
}

struct ContentView: View {
    
    @State private var words: [String] = []
    @State private var likeness: [Int] = []
    @State private var wordLikeness: [String:Int] = [:]
    @State private var StructLikeness: [Likenesses] = []
    
    var body: some View {
        Form {
            
            // Dict Method
            Section {
                ForEach(Array(wordLikeness.keys), id: \.self) { key in
                    Stepper(&quot;\(key)&quot;, value: $wordLikeness[key], in: 0...8, step: 1)
                }
            }
            
            // Arrays method
            Section {
                ForEach(0...words.count, id: \.self) { i in
                    Stepper(&quot;\(word[i])&quot;, value: $likeness[i], in: 0...8, step: 1)
                }
            }
            
            // Struct method
            Section {
                ForEach(StructLikeness, id: \.self) { s in
                    /*
                    Yes, I know structs are not references and pass copies around, this was another issue I was going to have to solve eventually, but for now, this gets the idea of what I was trying to solve with a struct
                    */
                    Stepper(&quot;\(s.word)&quot;, value: $s.likeness, in: 0...8, step: 1)
                }
            }
        }
    }
}

答案1

得分: 0

字典元素没有特定的顺序,所以在使用它们之前,您需要首先确定顺序,然后在ForEach中使用它们。例如,如果您想按键排序,

@State private var likenesses: [String: Int] = ["Foo": 3]
Form {
    Section {
        ForEach(likenesses.keys.sorted(), id: \.self) { key in
            Stepper("\(key): \(likenesses[key]!)", value: Binding($likenesses[key])!, in: 0...8, step: 1)
        }
    }
}

我更喜欢传递一个结构体数组。在创建ForEach时创建绑定,而不是在创建steppers时创建绑定。

@State private var likenesses: [Likenesses] = [...]
Form {
    Section {
        ForEach($likenesses) { s in
            Stepper("\(s.wrappedValue.word): \(s.wrappedValue.likeness)", value: s.likeness, in: 0...8, step: 1)
        }
    }
}

请注意,结构体应符合Identifiable

struct Likenesses: Identifiable {
    let word: String
    var likeness: Int = 0
    
    // 这里我使用word作为id
    var id: String { word }
}
英文:

Dictionary elements don't have a particular order, so you need to decide on an order first, before you use them in ForEach. For example, if you want to sort by the keys,

@State private var likenesses: [String: Int] = [&quot;Foo&quot;: 3]
Form {
    Section {
        ForEach(likenesses.keys.sorted(), id: \.self) { key in
            Stepper(&quot;\(key): \(likenesses[key]!)&quot;, value: Binding($likenesses[key])!, in: 0...8, step: 1)
        }
    }
}

I would prefer passing an array of structs instead. Create the binding when creating the ForEach, not when creating the steppers.

@State private var likenesses: [Likenesses] = [...]
Form {
    Section {
        ForEach($likenesses) { s in
            Stepper(&quot;\(s.wrappedValue.word): \(s.wrappedValue.likeness)&quot;, value: s.likeness, in: 0...8, step: 1)
        }
    }
}

Note that the struct should conform to Identifiable:

struct Likenesses: Identifiable {
    let word: String
    var likeness: Int = 0
    
    // here I&#39;m using word as the id
    var id: String { word }
}

huangapple
  • 本文由 发表于 2023年7月3日 09:39:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/76601424.html
匿名

发表评论

匿名网友

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

确定