https://github.com/DoyleHWorks/PokeDex
스크롤을 통해 포켓몬 목록을 탐색할 수 있는 앱에서, 보여지고 있는 포켓몬 중, 가장 위에 있는 포켓몬의 번호를 알 수 있도록 하는 기능을 구현했다. 그런데 No.1024~
에서 No.10002~
로 넘어가게 되는 문제가 발생했다.
기존의 코드는 다음과 같다:
private func updateTopPokemonLabel() {
guard let firstVisibleIndexPath = collectionView.indexPathsForVisibleItems.sorted(by: { $0.row < $1.row }).first else {
topPokemonLabel.text = "No.1~"
return
}
let pokemon = viewModel.pokemonItems.value[firstVisibleIndexPath.row]
if let id = pokemon.id {
topPokemonLabel.text = "No.\(id)~"
} else {
topPokemonLabel.text = "No.Unknown~"
}
}
indexPathsForVisibleItems
이 제대로 반환되지 않음private func updateTopPokemonLabel() {
guard let firstVisibleIndexPath = getFirstVisibleIndexPath() else {
topPokemonLabel.text = "No.1~"
return
}
// ViewModel 데이터 동기화 확인
guard firstVisibleIndexPath.row < viewModel.pokemonItems.value.count else {
topPokemonLabel.text = "No. ~"
return
}
let pokemon = viewModel.pokemonItems.value[firstVisibleIndexPath.row]
if let id = pokemon.id {
topPokemonLabel.text = "No.\(id)~"
} else {
topPokemonLabel.text = "No.Unknown~"
}
}
// 더 정확하게 IndexPath를 추출
private func getFirstVisibleIndexPath() -> IndexPath? {
guard let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else { return nil }
let visibleRect = CGRect(origin: collectionView.contentOffset, size: collectionView.bounds.size)
let visibleAttributes = layout.layoutAttributesForElements(in: visibleRect)
return visibleAttributes?.sorted(by: { $0.frame.origin.y < $1.frame.origin.y }).first?.indexPath
}
해결되지 않음
ID를 직접 추출했음해도 똑같은 현상이 발생하는 것으로 보아, 애초에 API로부터 가져올 수 있는 Pokemon ID에 10001
부터 시작하는 인덱스가 함께 존재함을 추측하게 됨. 확인해보니 실제로 그러함.
문제가 아닌 기존 사양임을 파악하였음.
사실 ID가 10001
부터 시작하는 경우는 처음부터 생각했었는데 그 가능성을 얕보고 문제를 해결하려고 한 느낌이 없잖아 있었다.
문제 접근 1을 통해 추가한 데이터 동기화 확인 코드때문에 새 아이템들을 로드할 때 아주 짧은 시간 No. ~
로 보이면서 깜빡이었기에 이는 다시 삭제하였다.