RPa*_*l99 4 dictionary swift swiftui
Is there a way to iterate through a Dictionary in a ForEach loop? Xcode says
Generic struct 'ForEach' requires that '[String : Int]' conform to 'RandomAccessCollection'
so is there a way to make Swift Dictionaries conform to RandomAccessCollection, or is that not possible because Dictionaries are unordered?
One thing I've tried is iterating the dictionary's keys:
let dict: [String: Int] = ["test1": 1, "test2": 2, "test3": 3]
...
ForEach(dict.keys) {...}
Run Code Online (Sandbox Code Playgroud)
But keys is not an array of Strings, it's type is Dictionary<String, Int>.Keys (not sure when that was changed). I know I could write a helper function that takes in a dictionary and returns an array of the keys, and then I could iterate that array, but is there not a built-in way to do it, or a way that's more elegant? Could I extend Dictionary and make it conform to RandomAccessCollection or something?
小智 83
You can sort your dictionary to get (key, value) tuple array and then use it.
struct ContentView: View {
let dict = ["key1": "value1", "key2": "value2"]
var body: some View {
List {
ForEach(dict.sorted(by: >), id: \.key) { key, value in
Section(header: Text(key)) {
Text(value)
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
paw*_*222 27
在 WWDC21 上,Apple 宣布了Collections其中包含的软件包OrderedDictionary(除其他外)。
现在,我们只需要替换:
let dict: [String: Int] = ["test1": 1, "test2": 2, "test3": 3]
Run Code Online (Sandbox Code Playgroud)
和:
let dict: OrderedDictionary = ["test1": 1, "test2": 2, "test3": 3]
Run Code Online (Sandbox Code Playgroud)
或者,我们可以从另一个初始化:
let dict: [String: Int] = ["test1": 1, "test2": 2, "test3": 3]
let orderedDict = OrderedDictionary(uniqueKeys: dict.keys, values: dict.values)
Run Code Online (Sandbox Code Playgroud)
请注意,由于dict是无序的,因此您可能需要对其进行排序orderedDict以强制执行一致的顺序。
以下是我们如何在 SwiftUI 视图中使用它的示例:
import Collections
import SwiftUI
struct ContentView: View {
let dict: OrderedDictionary = ["test1": 1, "test2": 2, "test3": 3]
var body: some View {
VStack {
ForEach(dict.keys, id: \.self) {
Text("\($0)")
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
注意:目前作为单独的包Collections提供,因此您需要将其导入到您的项目中。
您可以在这里找到更多信息:
And*_*era 20
由于它是无序的,唯一的方法就是将它放入一个数组中,这很简单。但是数组的顺序会有所不同。
struct Test : View {
let dict: [String: Int] = ["test1": 1, "test2": 2, "test3": 3]
var body: some View {
let keys = dict.map{$0.key}
let values = dict.map {$0.value}
return List {
ForEach(keys.indices) {index in
HStack {
Text(keys[index])
Text("\(values[index])")
}
}
}
}
}
#if DEBUG
struct Test_Previews : PreviewProvider {
static var previews: some View {
Test()
}
}
#endif
Run Code Online (Sandbox Code Playgroud)
如果您使用swift-collection的 OrderedDictionary (OrderedCollections 的一部分),您可以执行以下操作:
var states: OrderedDictionary<Player, String>
ForEach(states.elements, id:\.key) { player, state in
PlayerRow(player: player, state: state)
}
Run Code Online (Sandbox Code Playgroud)
确保关键对象是可识别的,否则请调整 ForEach 上的 id 参数。
简单的回答:不。
正如您正确指出的那样,字典是无序的。ForEach监视他的收藏中的更改。此更改包括插入,删除,移动和更新。如果发生任何这些更改,将触发更新。参考:https : //developer.apple.com/videos/play/wwdc2019/204/ at 46:10:
ForEach自动监视其收藏中的更改
我建议你看说话:)
您不能使用ForEach,因为:
UITableView,可以回收单元的情况下,重用单元,a List支持UITableViewCells,我认为a ForEach在做相同的事情),它需要计算要显示的单元。它通过查询数据源的索引路径来实现。从逻辑上讲,如果数据源是无序的,则索引路径是无用的。Xcode: 11.4.1~
...
var testDict: [String: Double] = ["USD:": 10.0, "EUR:": 10.0, "ILS:": 10.0]
...
ForEach(testDict.keys.sorted(), id: \.self) { key in
HStack {
Text(key)
Text("\(testDict[key] ?? 1.0)")
}
}
...
Run Code Online (Sandbox Code Playgroud)
更多详情:
final class ViewModel: ObservableObject {
@Published
var abstractCurrencyCount: Double = 10
@Published
var abstractCurrencytIndex: [String: Double] = ["USD:": 10.0, "EUR:": 15.0, "ILS:": 5.0]
}
struct SomeView: View {
@ObservedObject var vm = ViewModel()
var body: some View {
NavigationView {
List {
ForEach(vm.abstractCurrencytIndex.keys.sorted(), id: \.self) { key in
HStack {
Text(String(format: "%.2f", self.vm.abstractCurrencyCount))
Text("Abstract currency in \(key)")
Spacer()
Text(NumberFormatter.localizedString(from: NSNumber(value: self.vm.abstractCurrencytIndex[key] ?? 0.0), number: .currency))
}
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)