24

I have this code:

VStack {
    ForEach(0...2) { i in
        HStack {
            ForEach(0...2) { j in
                Text("test")
            }
        }
    }
}

This give me error Cannot convert value of type 'ClosedRange<Int>' to expected argument type 'Range<Int>' on both ForEach statements

I've seen threads on this error and kind of get it a bit on how the range thing works but not really. I'm wondering how to fix this error.

jellyshoe
  • 431
  • 1
  • 4
  • 8

2 Answers2

28

It is possible to use ClosedRange but with different ForEach constructor, providing id, like

    VStack {
        ForEach(0...2, id: \.self) { i in
            HStack {
                ForEach(0...2, id: \.self) { j in
                    Text("test")
                }
            }
        }
    }
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • 1
    `id: \.self` is a mistake that leads to memory leaks, the docs state `id` needs to be a property of the data, it can't be the data itself. – malhal Aug 02 '21 at 20:11
  • @malhal can you provide a link to the docs stating that? Apple in fact use `\.self` in many of their examples, for example: https://developer.apple.com/documentation/swiftui/foreach/menuindicator(_:) – Patrick Apr 18 '22 at 09:02
  • 1
    https://developer.apple.com/documentation/swiftui/foreach/init(_:id:content:)-82hm4 "id - The key path to the provided data’s identifier." If you decompile ForEach in Hopper you'll see the range init is a very different code path from the others. – malhal Apr 18 '22 at 13:22
15

You can use ..< instead of ... for range to be of type Range<Index> instead of ClosedRange<Index>

 VStack {
        ForEach(0..<2) { i in
            HStack {
                ForEach(0..<2) { j in
                    Text("test")
                }
            }
        }
    }
Jawad Ali
  • 13,556
  • 3
  • 32
  • 49