I've got ForEach loop inside a picker widget, that suppose to iterate a list of items (handler.items
).
However, in reality, I get that the tags where not properly set and $arg = $0
instead of $arg = $0.components(separatedBy: " ")[0]
after debugging the problem, it seems that although i see the right number of items according to the list size ... the ForEach iterate all the items twice, thus causing duplicated tags where they suppose to be unique.
here's the code, any idea how come the iteration repeat itself ?
VStack {
Picker("items", selection: $arg) {
ForEach(handler.items , id: \.self, content: {
Text($0).tag($0.components(separatedBy: " ")[0])
})
}
}
and here's how handler.items are defined. it's actually a separated object that is visible from the view, and can be changed from swift native methods.
class myHandler: ObservableObject {
@Published var items = [String]()
}
when setting a breakpoint in the ForEach
statement, i could print this object
(lldb) p handler.items
([String]) $R1 = 2 values {
[0] = "aaa bbb cc 1.1.1.1"
[1] = "ddd eee ff 2.2.2.2"
}
When i put breakpoint inside the ForEach body, I could see that the breakpoint caught there 4 times, and printing the iterator value i Got this printouts:
aaa bbb cc 1.1.1.1
ddd eee ff 2.2.2.2
aaa bbb cc 1.1.1.1
ddd eee ff 2.2.2.2
CodePudding user response:
You need to have .pickerStyle(.wheel)
to make it work on ios devices. Here is the code I used for testing:
(on macos 12.3-beta, using xcode 13.3-beta, targets ios 15 and macCatalyst 12)
class MyHandler: ObservableObject {
@Published var items: [String] = ["aaa bbb cc 1.1.1.1", "ddd eee ff 2.2.2.2"]
}
struct ContentView: View {
@State var handler = MyHandler()
@State var arg = ""
var body: some View {
VStack {
Text(arg) // <-- to display arg
Picker("items", selection: $arg) {
ForEach(handler.items , id: \.self) { str in
let _ = print(str.components(separatedBy: " ")[0]) // <-- to print tag values
Text(str).tag(str.components(separatedBy: " ")[0])
}
}.pickerStyle(.wheel) // <--- here
}
}
}
CodePudding user response:
Well I suggest moving the strings to a custom enumeration
instead of your ObservableObject
. Setting the tag doesn't really need to be done then. And no duplicate entries
enum Items: String, CaseIterable, Identifiable {
case a = "aaa bbb cc 1.1.1.1"
case b = "ddd eee ff 2.2.2.2"
var id: Self { self }
}
struct ContentView: View {
@State var selection = Items.a
var body: some View {
Picker("Items", selection: $selection) {
ForEach(Items.allCases) { item in
Text(item.rawValue)
}
}
}
}