I’m still trying to get my head around Swift/SwiftUI, so apologies for what’s likely a really simple question. Consider this simple SwiftUI file:
import SwiftUI
struct sampleStruct {
let entryID: Int // comes from the system
let name: String
}
struct TestView: View {
var listEntries = [sampleStruct(entryID: 301, name: "Pete"),
sampleStruct(entryID: 5003, name: "Taylor"),
sampleStruct(entryID: 13, name: "Suzie")]
var body: some View {
VStack{
ForEach(listEntries, id: \.entryID) { idx in
Text(idx.name)
}
}
}
}
struct TestView_Previews: PreviewProvider {
static var previews: some View {
TestView()
}
}
Here’s my question: I’m looking for a simple way to add the position of the element in the array to the text field. I.e. instead of Pete, Taylor, Susie, I’d like to get:
1 Pete
2 Taylor
3 Suzie
I thought that this could do the trick:
...
VStack{
ForEach(listEntries, id: \.entryID) { idx in
Text( listEntries.firstIndex { $0.id == idx.entryID } )
Text(idx.name)
}
}
...
But, I’m getting the error "No exact matches in call to initializer".
Any help would be appreciated,
Philipp
>Solution :
The simplest approach would be to use enumerated(), which returns a sequence of pairs (index and item):
struct TestView: View {
var listEntries = [sampleStruct(entryID: 301, name: "Pete"),
sampleStruct(entryID: 5003, name: "Taylor"),
sampleStruct(entryID: 13, name: "Suzie")]
var body: some View {
VStack{
ForEach(Array(listEntries.enumerated()), id: \.1.entryID) { (index,item) in
Text("\(index + 1) \(item.name)")
}
}
}
}
Note that for extremely large collections you might want a different approach for performance reasons, but for anything reasonably sized, this will work well. A quick and easy upgrade to it would be to used indexed() from Swift Algorithms in place of .enumerated() (you could omit the Array(...) wrapper if you did this as well.
If for learning purposes you want to see what you’d have to do to adjust your original approach, you’d want to:
- Use
.entryIDinstead of.id, which doesn’t exist on your model - Provide a default index in case
firstIndexreturnsnil - Interpolate the result into a
String
One solution might look like this:
struct TestView: View {
var listEntries = [sampleStruct(entryID: 301, name: "Pete"),
sampleStruct(entryID: 5003, name: "Taylor"),
sampleStruct(entryID: 13, name: "Suzie")]
var body: some View {
VStack{
ForEach(listEntries, id: \.entryID) { item in
let index = listEntries.firstIndex { $0.entryID == item.entryID } ?? -1
Text("\(index + 1) \(item.name)")
}
}
}
}