TV Series API를 가지고 와서 CollectionView에서 보여주는 과정 중에 오류가 생겨서 이 오류에 대해서 이야기해보려고 한다.
혼란스러운 부분은
어떤 TV Series는 오류가 안나고 잘 작동하고, 어떤 TV Series의 경우에만 오류가 나는게 문제였다.
해당 상황과 같이 두번째 작품에서는 제대로 Season과 Episode 정보를 불러온다면 첫번째 작품에서는 작품을 선택하자마자 런타임 오류가 발생한다.
해당 오류의 내용은 아래와 같다.
Thread 1: "the cell returned from -collectionView:cellForItemAtIndexPath: does not have a reuseIdentifier - cells must be retrieved by calling -dequeueReusableCellWithReuseIdentifier:forIndexPath:"
대강 reuseIdentifier 문제라고 생각했는데, identifier자체에서는 문제가 없어서 한참 헤매다가 멘토님의 도움을 받았다.
Xcode에서 identifier문제라고 해서 identifier만 주구장창 봐서는 문제가 해결될 수 없다는 것을..깨달았다.
우선 오류가 났던 지점의 코드는 다음과 같다
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if epiInfo.count > 0 {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: EpisodeCollectionViewCell.identifier, for: indexPath) as? EpisodeCollectionViewCell else { return UICollectionViewCell() }
guard let epiURL = epiInfo[indexPath.section].episodes[indexPath.row].stillPath else { return UICollectionViewCell()}
let url = URL(string: "https://image.tmdb.org/t/p/original" + epiURL)
cell.epiPosterImageView.kf.setImage(with: url)
let epiNum = epiInfo[indexPath.section].episodes[indexPath.row].episodeNumber
let epiName = epiInfo[indexPath.section].episodes[indexPath.row].name
cell.epiTitleLabel.text = "\(epiNum) \(epiName)"
return cell
} else {
return UICollectionViewCell()
}
}
처음에는 예외처리 문제인줄 알았다. viewDidLoad의 시점과 cellForItemAt 메서드가 실행되는 시점이 거의 비슷한데 나는 API를 불러와야하는 시간이 필요하기 때문에 처음에 if문 없이 실행하면 epiInfo
에 빈배열만 있는 상태에서 cellForItemAt
이 실행되어서 index out of range 에러가 났다. 그래서 if문을 넣어서 epiInfo
가 비어있을 때는 빈 셀을 리턴하도록 했다. 이부분에서 문제가 생겼다고 생각했다.
하지만 해당 오류는 아래의 코드에서 발생했다.
guard let epiURL = epiInfo[indexPath.section].episodes[indexPath.row].stillPath else { return UICollectionViewCell()}
보통 옵셔널 처리를 할 때 나는 if let을 사용하는 것보다 guard let을 사용하는 편이다. 개인적으로 괄호가 덜 생겨서 좋아하는듯..
하지만 여기서 문제가 생긴 이유는 위에 이미 cell을 만들어줬는데 guard let epiURL
부분에서 epiURL(still image의 path이다)이 nil인 상황이 발생하면서 또 UICollectionViewCell()을 만들어 버렸기 때문이다.
이미 return할 cell이 있는데 또 빈셀을 return 하라고..? 이러면서 오류가 발생한 것이다. 아마 그래서 identifier가 겹치는 문제가 발생하고 해당 오류가 나타난 것 같다.
이 오류를 통해 깨달은 부분은 항상 guard let 을 쓰는게 해결책은 아니라는 것이다.
게다가 추가적으로 이미지뿐 아니라 다른 정보들도 많이 있는데 단지 이미지가 없다는 이유로 아예 빈셀을 내보내는 것도 사용자 관점에서 생각하면 좋은 방법은 아니라고 생각한다. 그렇게 되면 사용자 입장에서는 이미지가 없다는 이유로 아예 다른 정보도 차단되는 것이기 때문이다.
이러한 문제를 해결하기 위해 다음과 같이 코드를 수정했다.
if let epiURL = epiInfo[indexPath.section].episodes[indexPath.row].stillPath {
let url = URL(string: "https://image.tmdb.org/t/p/original" + epiURL)
cell.epiPosterImageView.kf.setImage(with: url)
} else {
cell.epiPosterImageView.backgroundColor = .black
}
해결한 방법은 우선 옵셔널 처리를 guard let이 아닌 if let을 사용해서 처리를 했다.
그리고 이미지가 없을 때는 이미지뷰의 배경색을 검정색으로 바꿔주는 방법을 사용함으로써 에피소드의 번호나 이름은 그대로 사용자가 볼 수 있도록 처리했다. 이렇게 처리하니 오류가 생기지 않고 잘 동작하는 것을 확인할 수 있었다.
해결된 시뮬레이터 화면은 다음과 같다.