반응형
SwiftUI에서 많이 하는 실수 - ForEach에서 id를 잘못 선택해 셀이 깜빡이거나 재배치되는 실수
SwiftUI의 ForEach/List는 내부 요소를 추적하기 위해 id를 사용합니다.
이 id가 안정적이지 않으면 diffing이 꼬여 셀 내용이 바뀌거나,
삭제/삽입 시 엉뚱한 애니메이션이 발생합니다.
1. 문제 원인
- 단순히 index를 id로 사용 (id: \.offset)
- 값이 계속 바뀌는 프로퍼티를 id로 지정
- 서버에서 고유 id를 내려주는데도 매번 새로운 UUID()를 생성
2. 나타나는 증상
- 특정 셀을 삭제했는데, 다른 셀의 내용이 바뀐 것처럼 보임
- 필터/정렬 후 스크롤 위치가 이상하게 점프
- 애니메이션이 엉뚱한 셀에 적용
3. 잘못된 코드 예시
struct Card {
var title: String
}
struct CardsView: View {
@State private var cards: [Card] = [
.init(title: "A"),
.init(title: "B"),
.init(title: "C")
]
var body: some View {
// ❌ index(offset)를 id로 사용
List(Array(cards.enumerated()), id: \.offset) { index, card in
Text(card.title)
}
}
}
- 중간 요소를 삭제/삽입하면 index 전체가 바뀌어,
SwiftUI 입장에선 “모든 셀의 id가 변경된 것”으로 보입니다.
4. 올바른 코드 예시
4-1. 고유 id를 가진 모델 사용
struct Card: Identifiable {
let id: UUID
var title: String
}
struct CardsView: View {
@State private var cards: [Card] = [
.init(id: UUID(), title: "A"),
.init(id: UUID(), title: "B"),
.init(id: UUID(), title: "C")
]
var body: some View {
// ✅ Identifiable일 경우 id 생략 가능
List(cards) { card in
Text(card.title)
}
}
}
4-2. 서버에서 받은 고유 id 사용하는 경우
struct CardDTO: Identifiable {
let id: Int // 서버의 고유 PK
let title: String
}
id로 id를 그대로 쓰면 됩니다.
5. 정리 및 팁
- id는 “요소의 생애 동안 변하지 않는 값”을 써야 합니다.
- index 사용은
- 정렬/필터/삽입/삭제가 전혀 없고
- 완전히 정적인 리스트일 때만 제한적으로 고려합니다.
- 서버/DB에 이미 고유 키가 있다면, 그 값을 그대로 SwiftUI의 id로 사용하는 것이 가장 좋습니다.
반응형

