728x90
SMALL
✅ 에러 분석 및 해결 방법
에러 메시지:
Expected dequeued view to be returned to the collection view in preparation for display.
When the collection view's data source is asked to provide a view for a given index path,
ensure that a single view is dequeued and returned to the collection view.
Avoid dequeuing views without a request from the collection view.
🚨 에러 원인:
- UICollectionView는 cell을 dequeue하면 반드시 반환해야 함
- 현재 dequeue한 cell을 configure()에서 반환하지 않고 있음
- configure() 내부에서 새로운 cell을 dequeue하고 있기 때문에 충돌 발생
- 즉, 한 번의 dequeue로 두 개의 cell을 반환하려고 하면서 충돌 발생
✅ 1. 문제 발생 코드 (dequeue를 두 번 실행)
dataSource = UICollectionViewDiffableDataSource<SearchSection, SearchItem>(collectionView: searchResultCollectionView) { searchResultCollectionView, indexPath, item in
// ✅ 여기서 이미 dequeue 실행
guard let cell = searchResultCollectionView.dequeueReusableCell(
withReuseIdentifier: SearchResultCell.reuseIdentifier,
for: indexPath
) as? SearchResultCell else {
return UICollectionViewCell()
}
cell.setViewModel(self.viewModel) // ✅ cell에 viewModel을 설정
switch item {
case .movie(let movie):
return self.configure(SearchResultCell.self, with: .movie(movie), for: indexPath) // ❌ 여기서 또 dequeue
case .tv(let tv):
return self.configure(SearchResultCell.self, with: .tv(tv), for: indexPath) // ❌ 여기서 또 dequeue
case .people(let person):
return self.configure(SearchResultCell.self, with: .people(person), for: indexPath) // ❌ 여기서 또 dequeue
}
}
🚨 문제:
- 이미 dequeue한 cell을 사용해야 하는데,configure() 내부에서 다시 dequeue를 실행해서 충돌 발생
private func configure<T: SelfConfiguringTVCell>(_ cellType: T.Type, with model: TvTMDBResult, for indexPath: IndexPath) -> T {
guard let cell = seriesCollectionView.dequeueReusableCell(withReuseIdentifier: cellType.reuseIdentifier, for: indexPath) as? T else { fatalError("Unable to deque \(cellType)")}
cell.configure(with: model)
return cell
}
✅ 2. 해결 방법: configure() 내부에서 dequeue하지 않도록 수정
🔹 수정 방법
1️⃣ configure() 내부에서 dequeue를 제거
2️⃣ 이미 dequeue한 cell을 configure()에 전달
private func createDataSource() {
dataSource = UICollectionViewDiffableDataSource<SearchSection, SearchItem>(collectionView: searchResultCollectionView) { [weak self] collectionView, indexPath, item in
guard let self = self else { return nil }
// ✅ `dequeue`를 한 번만 실행 (기존 코드 유지)
guard let cell = collectionView.dequeueReusableCell(
withReuseIdentifier: SearchResultCell.reuseIdentifier,
for: indexPath
) as? SearchResultCell else {
return UICollectionViewCell()
}
cell.setViewModel(self.viewModel) // ✅ `viewModel`을 한 번만 설정
// ✅ `configure()` 호출 시 `cell`을 직접 전달 (dequeue 제거)
switch item {
case .movie(let movie):
self.configure(cell, with: .movie(movie))
case .tv(let tv):
self.configure(cell, with: .tv(tv))
case .people(let person):
self.configure(cell, with: .people(person))
}
return cell // ✅ `dequeue`한 `cell`을 반환
}
}
✅ 3. configure()에서 dequeue 제거
private func configure(_ cell: SearchResultCell, with item: SearchItem) {
cell.configure(with: item)
}
🎯 🚀 최종 정리
✅ dequeueReusableCell을 한 번만 실행하도록 수정
✅ configure() 내부에서 dequeue하지 않고 기존 cell을 사용
✅ 충돌 없이 viewModel을 SearchResultCell에 전달 가능
✅ UICollectionView의 예상 동작을 따르므로 앱이 정상적으로 실행됨
728x90
LIST
'MovieClip' 카테고리의 다른 글
| 🔥 MVVM + Combine을 통한 검색기능 구현 1편 패턴 비교 (0) | 2025.02.24 |
|---|---|
| ✅ MVVM + Combine로 설계한 검색에서 번역 기능 적용하는 최적 방법 (0) | 2025.02.23 |
| 🚜 서치 기능 개선 (MVVM + Combine) (0) | 2025.02.22 |
| 🔍 클로저를 저장하는 변수로? (0) | 2025.02.21 |
| 📍 함수의 역할 -> createFeaturedSection() { } (0) | 2025.02.21 |