반응형

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로 사용하는 것이 가장 좋습니다.
반응형
Posted by 까칠코더
,