struct ForEach<Data, ID, Content> where Data : RandomAccessCollection, ID : Hashable
우리는 전 블로그을 통해
[ 구조체 ForEach의 특징 ]
1️⃣. <Data, ID, content>
2️⃣. where Data: RandomAccessCollection, ID : Hashable
3️⃣. RandomAccessCollection (랜덤 엑세스 콜렉션)
4️⃣. Hashable (해쉬블)
자, 이제는 ForEach의 예시를 통해 어떻게 사용했는 지 확인해보자!
애플 공식 홈페이지에 나와있는 예문으로 돌아가보자.
UI 실행은 위와 같이 된다.
이것의 예시 코드는 아래와 같다.
Section(header: Text("Attendees")) {
ForEach(scrum.attendees) { attendee in
Label(attendee.name, systemImage: "person")
}
}
의문을 하나 하나 풀어나가보자!
이때 짚고 넘어가야할 점은
C/C++에 익숙해있다보면 도대체 왜 구조체를 생성하였는데 View가 만들어지지? 라고 생각하기 쉬운데, SwiftUI에서 List처럼 View를 만들어주는 View Container역할을 하는 구조체라고 생각해야한다.
공식문서를 보면 List도 모두 Structure 되어있다.
이름은 forEach(:_)와 비슷하기에 반복문이라고 생각하기 쉬운데,
그런 의도로 이름을 그렇게 지은 듯 하지만 내부 Data를 기반으로 View를 계산해서 보여주는 것이다.
애플 공식문서 ForEach 안에 다양한 init가 있고, 이 중에 하단의 init을 사용하여 실행되었다.
ForEach(scrum.attendees) { attendee in
Label(attendee.name, systemImage: "person")
}
다시 위의 예시를 보면서 이야기를 하면,
첫번 째 인자로 Data는 scrum.attendees이 된 것이고,
두번 째 인자로서 ((Data.Element) -> Content) 클로저로
{ attendee in
Label(attendee.name, systemImage: "person")
}
를 받은 것이다.
그러면 scrum.attendees가 어떤 Type인 지 보자.
Data은 Hashable 프로토콜을 채택해야한다.
위에 SwiftUI 예제에서 scrum.attendees이 var attendees: [Attendee] 이다.
scrum.attendees는 Array이기에 RandomAccessCollection를 충족한다.
다음 조건은 충족하는 가?
Hashable이 아니라 Identifiable 프로토콜을 채택하였다??
-> Identifiable 프로토콜은 내부적으로 Hashable 프로토콜을 채택하고 있기 때문에, Identifiable 프로토콜을 사용하는 경우에는 ID 타입이 Hashable 프로토콜을 채택하면 된다.
그렇다고 ID는 Hashable 프로토콜을 채택하지 않았는데??
-> Identifiable 프로토콜을 채택한 객체에서 ID 타입은 Hashable 프로토콜을 채택해야 하지만, 이를 구현할 때 UUID 타입을 사용할 수 있습니다. Identifiable 프로토콜을 채택한 객체에서 ID 타입을 UUID 타입으로 지정하여 구현하면, 이를 사용하는 SwiftUI의 List나 ForEach와 같은 뷰에서도 모델의 고유성을 보장할 수 있다고 한다.
Identifiable 프로토콜은 각 데이터가 각자를 식별할 수 있는 무언가를 가지고 있는 경우에 충족한다고 볼 수 있다.
scrum.attendees는 Identifiable를 충족한다.
이를 통해 ForEach가 어떤 Data를 충족하는 지 확인해보았다.
ForEach를 쓰는데 도대체 Hashable과 Identificable을 어떻게 처리해야하나 고민했는데 조금 더 수월하게 사용할 수 있지 않을까 싶다.
애플 스유 Documentation을 그냥 슬렁 슬렁 넘어가면 그냥 타자연습 밖에 안되지만 하나 하나 뜯어보면 분명 더 많이 얻을 수 있을 것 같다.