ForEach

요구에 따라 Identified Data의 기본 Colletion로부터 뷰를 계산하는 Structure

struct ForEach<Data, ID, Content> where Data : [RandomAccessCollection](https://developer.apple.com/documentation/Swift/RandomAccessCollection), ID : [Hashable](https://developer.apple.com/documentation/Swift/Hashable)

  • Data는 RandomAccessCollection을 준수해야한다.
  • ID는 Hashable을 준수해야한다.

 

ForEach에서 id를 쓰는 이유

init(
    _ data: Data,
    @ViewBuilder content: @escaping (Data.Element) -> Content
)

 

기본 Initailizer에서 data는 Identifiable 프로토콜을 준수해야한다. (각 View들을 식별하기 위해)

하지만, [Int]와 같은 Identifiable을 준수하지 않는 데이터 유형은 data에 넣을 수 없다.

그래서 넣어보면 컴파일 에러가 생긴다. (Cannot convert value of type '[Int]' to expected argument type 'Range’)

이를 해결하기 위해 id가 존재하는 initalizer를 사용한다.

 

init(
    _ data: Data,
    id: KeyPath<Data.Element, ID>,
    @ViewBuilder content: @escaping (Data.Element) -> Content
)

 

해당 initializer에서는 data가 꼭 Identifieable을 준수할 필요가 없다.

id가 그 역할을 대신하기 때문이다.

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값을 통해서 뷰를 구별한다.

 

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 프로토콜을 준수하도록 함을 권장한다.

 

How to allow ForEach layout item to show duplicate item from array in SwiftUI?

I am working with on multiple choose answer quiz app. var itemsTemp = ["ant","bat", "bear", "bee", "bird", "butterfly", "camel", &

stackoverflow.com

 

다음과 같은 구조체를 생성해서 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)
            }
        }
    }
}

 

+ Recent posts