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)
}
}
}
}
'SwiftUI' 카테고리의 다른 글
[SwiftUI] 하위뷰에서 상위뷰로 데이터 전달 (PreferenceKey, GeometryReader) (2) | 2023.10.08 |
---|