'SwiftUI ForEach statement iterate the list twice

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

EDIT : here's a minimal reproducible example. notice the circled text that clearly shows that the arg didn't get the tag expression but the whole item : enter image description here



Solution 1:[1]

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

Here’s an example from Apple

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)
            }
        }

    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1