I am trying to create a PickerView which has sections
each item conforms to "id" and I am tagging the Text with the item's id (which is unique and I verified that there are no clashes)
The PickerView seems to disregard the tags I am assigning and chooses all rows with the same corresponding index for each section
I also tried tagging each item with a random UUID to check the behavior and it seems to continue
struct ExperimentPickerView: View {
@StateObject var localExperiment = RunningExperiment.active
@StateObject var experiments = RemoteExperiments.instance
@State var picked : Int = -1
var body: some View {
Picker("active", selection: $picked) {
ForEach(Array(experiments.experiments.enumerated()), id: \.offset) { i,experiment in
Section(header: Text("\(experiment.name)")) {
ForEach(Array(experiment.variations.enumerated()), id: \.offset) { j,variation in
// Text("\(variation.name) \(variation.id)").tag(variation.id)
Text("\(variation.name) \(variation.id)").tag(UUID().description)
}
}
}
}.id(picked).onReceive([self.picked].publisher.first()) { (value) in
print(value) // prints the row number and not the id of the element
}
}
}
struct Experiment : Codable, Equatable, Identifiable {
var id: Int {
var hasher = Hasher()
name.hash(into: &hasher)
variations.hash(into: &hasher)
return hasher.finalize()
}
let name : String
let variations: [Variation]
enum CodingKeys: String, CodingKey {
case name
case variations
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let n = try container.decode(String.self, forKey: .name)
name = n
let a = try container.decode(AnyCodable.self, forKey: .variations)
print(a)
let b = a.value as! [[String:Any]]
var vars = [Variation]()
for v in b {
if let na = v["name"], let nna = na as? String {
vars.append(Variation(name: nna, experiment: n))
}
}
variations = vars
}
}
struct Variation: Codable, Equatable, Identifiable, Hashable {
var id: Int {
var hasher = Hasher()
name.hash(into: &hasher)
experiment.hash(into: &hasher)
let hashValue = hasher.finalize()
return hashValue
}
let name: String
var experiment: String
enum CodingKeys: String, CodingKey {
case name, experiment
}
}
The
tagshould be same type asselection, because it is used to match picked row. Andidshould not be modified in this scenario, because it reinitialises picker completely.Provided code is not testable so here is just a demo of solution (simplified replication of your scenario).
Tested with Xcode 12.1 / iOS 14.1.