본문 바로가기
감정일기(가칭)

📱 UICollectionView 내부 셀의 날짜 갱신이 안 되는 이유와 해결 방법— 특히 “셀 자체를 전달하는 방식”의 강력함

by 밤새는 탐험가89 2025. 12. 10.
728x90
SMALL

iOS에서 작성 화면(UICollectionView 기반) 안에 또 다른 UICollectionView를 두고, 날짜나 이미지처럼 상태를 업데이트해야 하는 경우가 있습니다.

이번 글에서는 실제 구현 중 겪었던 문제를 기반으로, **“날짜 선택 이후 셀이 올바르게 업데이트되지 않는 문제”**를 어떻게 해결했는지를 정리합니다.

특히 핵심 해결책인
👉 “IndexPath 기반 접근을 버리고, 셀 인스턴스를 직접 전달하는 방식”
이 얼마나 강력하고 안전한지 중점적으로 설명합니다.

 

❗ 문제 상황

아래 구조를 가진 감정일기 작성 화면이 있다고 합시다.

WriteCollectionView (외부)
 ┗ DiaryWriteDateAndGalleryCell (내부 셀)
     ┗ internalCollectionView (2개의 섹션)
         ┣ Date Section → 날짜 셀
         ┗ Gallery Section → 이미지 셀

 

사용자가 날짜 셀을 탭하면 DatePicker가 뜨고, 날짜 선택 시 해당 셀만 업데이트되길 원했습니다.

그래서 아래와 같이 구현했습니다.

let targetIndexPath = IndexPath(item: 0, section: 0)

if let cell = writeCollectionView.cellForItem(at: targetIndexPath) as? DiaryWriteDateAndGalleryCell {
    cell.updateDate(date)
}

 

하지만…
날짜는 콘솔에 찍히는데 UI에 반영이 되지 않는 문제가 발생했습니다.

 

🔍 원인 분석

문제의 핵심은 “IndexPath를 추측해서 셀을 찾았다”는 점입니다.

  • 화면 구조가 바뀌면 IndexPath가 달라짐
  • 스크롤 또는 레이아웃 변경 중이라 셀을 로드하지 않았을 수도 있음 (cellForItem(at:) → nil)
  • 재사용 셀 구조상 configure가 이후에 다시 호출되면서 업데이트를 덮어써버림

즉, IndexPath 기반 접근은 매우 취약합니다.
특히 셀 내부에 또 다른 CollectionView가 있는 경우에는 더더욱.

그 결과:

  1. cell.updateDate() 가 실제로 실행되지 않거나
  2. 실행되었더라도 configure()가 다시 호출되어 상태가 덮어써짐

그래서 날짜가 표시되지 않았던 겁니다.

 

💡 해결 방법: “셀을 직접 전달하자”

핵심 아이디어는 아주 단순합니다.

 

어떤 셀에서 날짜 선택 UI를 열었는지 그 셀 자신만 알고 있다.
그렇다면 그 셀을 그대로 전달해서 업데이트하면 된다.

 

즉, IndexPath로 셀을 다시 찾을 필요 자체가 사라진다.

 

🛠 방법 1: setupDatePicker(attachedTo cell:) 패턴

① DateCell → 부모 셀(DiaryWriteDateAndGalleryCell) → VC로 콜백 전달

이전에는 onTapDate 클로저가 단순히 이벤트만 넘겼다면,
이제는 탭된 셀 자신을 그대로 넘기도록 구조를 바꾼다.

cell.onTapDate = { [weak self, weak cell] in
    guard let self, let cell else { return }
    self.setupDatePicker(attachedTo: cell)
}

 

여기서 중요한 것은

weak cell을 캡처하여 정확한 셀 인스턴스를 전달한다는 점입니다.

 

② setupDatePicker(attachedTo:)에서 셀 직접 업데이트

func setupDatePicker(attachedTo cell: DiaryWriteDateAndGalleryCell) {
    let calendarVC = CustomCalendarViewController()

    calendarVC.onDateSelected = { [weak self, weak cell] date in
        guard let self, let cell else { return }

        self.diaryWriteVM.editableDiary.createdAt = date

        // 핵심: 전달받은 셀에 직접 업데이트
        cell.updateDate(date)
    }

    present(calendarVC, animated: true)
}

 

✨ 왜 이 방식이 절대적으로 안전한가?

✔ 1. IndexPath 의존 0%

  • 셀의 위치가 바뀌어도
  • 화면 구성이 바뀌어도
  • 스크롤 상태와 무관하게

셀 인스턴스 자체는 언제나 정확합니다.

 

✔ 2. 실시간으로 UI 반영

  • reloadItems나 reloadData 필요 없음
  • 영향을 받는 건 내부 CollectionView의 특정 섹션뿐
  • 텍스트, 이미지, 스크롤 위치 모두 유지됨

✔ 3. 재사용 셀 문제에서도 안전

configure가 다시 호출되어도 selectedDate가 직접 관리되기 때문에 상태가 사라지지 않습니다.

 

DateCell.tap → onTapDate(cell 전달)
      ↓
DiaryWriteViewController.setupDatePicker(attachedTo:)
      ↓
날짜 선택 완료 onDateSelected
      ↓
attached cell.updateDate()
      ↓
internalCollectionView.reloadSections([.date])
      ↓
UI 즉시 반영
728x90
LIST