endPoint 변경
endPoint 변경을 통해 page값으로 int를 사용하고 있음. 이를 파라미터로 받아야 함.
기존의 코드 내 파라미터에서 page를 받도록 함.
func fetchMovies(page: Int, completion: @escaping (Result<MovieResponse, Error>) -> Void){
let requestURL = URL(string: "https://api.themoviedb.org/3/movie/popular?api_key=\(APIKey.apiKey)&page=\(page)")
// 중략
}
api변경하였음. 그런데 스크롤을 내릴 때마다 page를 변경해줘야하는데 어떻게 변경해줄 수 있을가?
scroll을 완전히 다 내렸을 때, page의 int 값을 변경해줌
어떻게 모든 scroll을 내렸음을 알 수 있을까?
처음 scrollViewDidScroll을 사용하여 구현하고자 하였다. 그러나 스크롤 하단을 데이터가 기준이 아니라, view.frame이 되니 기계마다 표시의 오류가 발생할 수 있음.
그래서 데이터를 기준으로 다음 페이지를 넘기는 방법을 선택함. collectionview의 indexpath.row의 값을 model.count와 비교하기로함.
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if indexPath.row == viewModel.movie.count - 1{
loadData()
}
}
func loadData(){
currentPage += 1
viewModel.fetchMovies(page: currentPage) {
self.mainView.collectionView.reloadData()
}
}
indexpath.row 하단에 내려갔을 경우, loadData() 를 통해 fetchMovie를 실행하면 정상적으로 다음 데이터가 표시될줄 알았음.
그러나 fetchMovie의 성공할 경우, 기존 model 데이터에 append 되는 것이 아니라, movie 자체의 데이터 덮어씀. 계속해서 스크롤을 내리니 해당 뷰의 이미지가 계속해서 내려가지 않고, 바뀌는 기현상을 경험했음.
결국 loadData()가 호출될 경우는 기존 movie model에 append 하는 것을 선택함.
//viewModel.swift
func appendMovies(page: Int, completion: @escaping () -> Void) {
apiManager.fetchMovies(page: page) { [weak self] result in
DispatchQueue.main.async {
switch result {
case .success(let response):
self?.movie.append(contentsOf: response.results)
completion()
case .failure(let error):
print("Error: \(error)")
}
}
}
}
데이터가 성공적으로 덮어졌으나, page 3까지만 보여줌.
Error: keyNotFound(CodingKeys(stringValue: "release_date", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "results", intValue: nil), _JSONKey(stringValue: "Index 7", intValue: 7)], debugDescription: "No value associated with key CodingKeys(stringValue: \"release_date\", intValue: nil) (\"release_date\").", underlyingError: nil))
release_date 키 값을 찾지 못했음. 보유하고 있는 항목의 데이터가 없을 줄 생각도 못함.
옵셔널로 처리하니 문제 없이 표시됨.
struct Movie: Codable {
let title: String
let posterPath: String?
let releaseDate: String?
let voteAverage: Double
let overview: String
enum CodingKeys: String, CodingKey{
case title
case posterPath = "poster_path"
case releaseDate = "release_date"
case voteAverage = "vote_average"
case overview
}
}