이번 포스팅에서는 SwiftUI의 List에 대해 알아보겠습니다. UIKit의 UITableView와 동일한 역할을 하는 객체라고 보면 됩니다.
선언하는 방법은 List 안에 해당 리스트에 들어갈 객체들을 넣어주면 됩니다.
import SwiftUI
struct ContentView: View {
var body: some View {
List {
Text("First Line")
Text("Second Line")
Text("Third Line")
Text("Fourth Line")
Text("Fifth Line")
Text("Sixth Line")
Text("Seventh Line")
}
}
}
위처럼 직접 들어갈 요소들을 넣어서 선언하는 방법도 있지만 실전에서는 거의 사용하지 않는 방법입니다. 실제 개발을 할 때는 대부분 Data를 View 외부에서 배열의 형태로 받아와서 List로 보여주는 경우가 대부분입니다. 이 경우에는 ForEach문을 사용하는 경우가 많습니다.
ForEach문을 사용할 때 주의할 점은 배열에 들어있는 객체들이 각각 Identifiable 프로토콜을 준수해야 한다는 점입니다. Identifiable은 객체의 인스턴스에 다른 인스턴스와 구분될 수 있도록 해주는 프로토콜입니다.
객체를 Identifiable을 준수하게 만드는 가장 쉬운 방법은 당연하게도 Identifiable 프로토콜을 직접 준수하게 하는 법입니다. Identifiable 프로토콜을 준수하기 위해서는 id 속성이 있어야 합니다. id 속성은 인스턴스가 고유하게 가지는 값이어야 합니다. (다른 인스턴스와 겹치지 않도록!)
아래 Identifiable을 준수하는 struct를 통해 학생들의 이름과 점수를 List에 표현해보겠습니다.
struct Student: Identifiable {
let id = UUID()
let name: String
let grade: Int
}
let students = [
Student(name: "Kim", grade: 23),
Student(name: "Lee", grade: 65),
Student(name: "Park", grade: 47),
Student(name: "Choi", grade: 85),
Student(name: "Jung", grade: 45),
Student(name: "Moon", grade: 100),
Student(name: "Sung", grade: 12),
]
struct ContentView: View {
var body: some View {
List {
ForEach(students) { student in
Text("\(student.name)의 점수는 \(student.grade)점입니다.")
}
}
}
}
이번에는 Identifiable을 준수하는 대신 id로 쓸 속성을 ForEach문의 인자로 전달하는 방법입니다. Identifiable의 id와 동일하게 전달하는 id 값은 인스턴스마다 고유한 값을 가져야 합니다.
만약에 학생들의 이름이 절대 겹치지 않는다고 가정합니다. 그런 경우 아래처럼 id 값으로 name 속성을 전달해서 Identifiable을 준수한 것과 동일한 효과를 얻을 수 있습니다.
import SwiftUI
struct Student {
let name: String
let grade: Int
}
let students = [
Student(name: "Kim", grade: 23),
Student(name: "Lee", grade: 65),
Student(name: "Park", grade: 47),
Student(name: "Choi", grade: 85),
Student(name: "Jung", grade: 45),
Student(name: "Moon", grade: 100),
Student(name: "Sung", grade: 12),
]
struct ContentView: View {
var body: some View {
List {
ForEach(students, id: \.self.name) { student in
Text("\(student.name)의 점수는 \(student.grade)점입니다.")
}
}
}
}
id를 해당 인스턴스 자체를 사용할 수도 있습니다. 이 경우에는 해당 객체가 Hashable 프로토콜을 준수해야 합니다. Hashable 프로토콜을 준수하는 타입은 정수 해쉬값을 제공하는 타입입니다. 다른 말로 하면 각각의 인스턴스가 고유한 값을 가진다는 의미입니다. 즉 해당 해쉬값이 id의 역할을 할 수 있는 것이죠.
import SwiftUI
struct Student: Hashable {
let name: String
let grade: Int
}
let students = [
Student(name: "Kim", grade: 23),
Student(name: "Lee", grade: 65),
Student(name: "Park", grade: 47),
Student(name: "Choi", grade: 85),
Student(name: "Jung", grade: 45),
Student(name: "Moon", grade: 100),
Student(name: "Sung", grade: 12),
]
struct ContentView: View {
var body: some View {
List {
ForEach(students, id: \.self) { student in
Text("\(student.name)의 점수는 \(student.grade)점입니다.")
}
}
}
}
배열의 인덱스 역시 고유한 값이라고 볼 수 있습니다. 해당 인덱스에 속하는 element는 단 1개로 특정됩니다.
import SwiftUI
struct Student: Hashable {
let name: String
let grade: Int
}
let students = [
Student(name: "Kim", grade: 23),
Student(name: "Lee", grade: 65),
Student(name: "Park", grade: 47),
Student(name: "Choi", grade: 85),
Student(name: "Jung", grade: 45),
Student(name: "Moon", grade: 100),
Student(name: "Sung", grade: 12),
]
struct ContentView: View {
var body: some View {
List {
ForEach(0..<students.count) { i in
Text("\(students[i].name)의 점수는 \(students[i].grade)점입니다.")
}
}
}
}