ForEach View를 사용할 때 ID로 \.self를 넣어주고는 한다.
struct ContentView: View { let colors: [Color] = [.red, .green, .blue] var body: some View { VStack { ForEach(colors, id: \.self) { color in Text(color.description.capitalized) .padding() .background(color) } } } }
ForEach로 생성되는 각 뷰들이 생성되거나 삭제될 때 그 부분만 업데이트하기위해 ID값을 통해서 뷰를 구별한다.
이를 위해서 id인자를 넣어주게 된다.
public init(_ data: Data, id: KeyPath<Data.Element, ID>, @ViewBuilder content: @escaping (Data.Element) -> Content)
ForEach 뷰에 전달하는 id인자는 keyPath로 전달하게 되는데, 참조한 keyPath를 통해
data에서 가져온 값을 unique identifier로 결정지어 각 뷰가 구별되도록한다.
때문에 위 예시에서 \Color.self 를 생략한 \.self를 전달했으므로 각 뷰의 unique identifier는 차례대로.red, .green, .blue가 된다.
그렇다면, data의 각 요소가 같다면 어떻게 해야할까?
예를들어 colors 배열이 다음과 같은 경우를 말한다.
let colors: [Color] = [.red, .red, .blue]
한 스택 오버플로우 답변 에서는 struct 구조체로 감싸서 Identifiable 프로토콜을 준수하도록 함을 권장하고있다.
다음과 같은 구조체를 생성해서 UUID() 함수를 통해 unique identifier을 생성한다.
struct MyColor: Identifiable { var id = UUID() var color: Color }
다음과 같이 keyPath를 .id로 전달해서 각 view가 unique해지도록 한다.
struct ContentView: View { let colors: [MyColor] = [.init(color: .red), .init(color: .red), .init(color: .blue)] var body: some View { VStack { ForEach(colors, id: \.id) { myColor in Text(myColor.color.description.capitalized) .padding() .background(myColor.color) } } } }