안녕하세요. Deah 입니다.
오늘은 뭅챠 프로젝트에서 인기급상승 탭을 만들어보려고 해요!
바로 시작해보겠습니다. 🏃♀️
✨ 작업일시: 2024-06-10 (Mon)
인기급상승 탭에서는 TMDb Trending API - All을 사용하여 영화, 드라마, 시리즈 구분없이 트렌딩이 높은 콘텐츠를 전부 노출해주려고 합니다.
(매번 빌드할 때 마다 인기급상승 탭을 누르기가 귀찮아서 잠시 홈 탭으로 위치를 옮겨두었다.....)
콘텐츠가 노출될 테이블 뷰를 만들고 그 안에 셀에서 개봉 날짜, 장르, 대표 이미지, 평점, 콘텐츠 타이틀, 줄거리 등이 들어갈 수 있도록 레이아웃을 잡아주었습니다. 그리고 추후에 셀을 클릭하여 상세 화면으로 넘어갈 수 있도록 만들어줄 예정이기 때문에 클릭을 유도하는 자세히 보기와 버튼 로고도 함께 넣어주었어요.
struct Trending: Decodable {
let page: Int
let results: [TrendingResults]
let total_pages: Int
let total_results: Int
}
struct TrendingResults: Decodable {
let id: Int
let title: String?
let name: String?
let original_title: String?
let overview: String
let poster_path: String
let backdrop_path: String
let media_type: String
let adult: Bool
let original_language: String
let genre_ids: [Int]
let popularity: Double
let release_date: String?
let first_air_date: String?
let video: Bool?
let vote_average: Double
let vote_count: Int
}
func callRequest() {
let header: HTTPHeaders = [
"Authorization": API.KEY.kmdb,
"accept": "application/json"
]
AF.request(API.URL.trending,
method: .get,
encoding: JSONEncoding.default,
headers: header)
.responseDecodable(of: Trending.self) { res in
switch res.result {
case .success(let value):
print("성공")
self.trendingList = value.results // 성공했을 때 데이터 저장
self.trendingTableView.reloadData() // 테이블 뷰 리로드!
case .failure(let error):
print("실패")
print(error)
}
}
}
사용할 데이터의 구조체를 만들고 결과로 받아온 값을 디코딩하여 사용할 수 있도록 해주었습니다.
cellForRowAt에서 Cell한테 indexPath.row에 맞는 데이터를 넘겨주고,
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: TrendingTableViewCell.id, for: indexPath) as! TrendingTableViewCell
let idx = indexPath.row
let trendingData = trendingList[idx]
cell.selectionStyle = .none
cell.configureCellHierarchy()
cell.configureCellLayout()
cell.configureCellUI()
cell.configureCellData(data: trendingData)
return cell
}
Cell에서는 아래와 같이 받아서 각 뷰 객체에 데이터를 넣어주었습니다.
func configureCellData(data: TrendingResults) {
openDateLabel.text = data.release_date ?? data.first_air_date
genreLabel.text = "#Mystery"
voteLabel.text = Text.Trending.vote
voteAverage.text = "\(data.vote_average)"
let poster = URL(string: "\(API.URL.kmdbImg)\(data.poster_path)")
cardImg.kf.setImage(with: poster)
titleLabel.text = data.title ?? data.name
overviewLabel.text = data.overview
detailLabel.text = Text.Trending.detail
detailImgView.image = SystemImage.front
}
1차적으로 필요한 데이터들은 개봉일, 장르, 이미지, 평점, 제목, 줄거리 정도였는데 각 영화 정보마다 제목이 없거나 개봉일이 없는 값들이 있어서 옵셔널 처리를 해준 다음, 값이 없을 땐 대체 데이터를 출력할 수 있도록 했습니다!
- 개봉일이 없을 때(release_date) → 첫 상영일정으로(first_air_dat)
- 제목이 없을 때(title) → 이름으로(name)
그리고 genreLabel에는 아직 문자열로 하드코딩 되어있는데, 장르 같은 경우는 문자열로 바로 응답값이 오는 게 아니라 배열에 각 장르 코드가 담겨와서, 코드를 다시 해당하는 문자열로 변환하는 과정이 추가로 필요합니다! (TMDb 정말 번거롭네....)
Alamofire 라이브러리로 영화/드라마 장르 API 호출 응답값으로 데이터를 만들어서, 해당 데이터 구조에서 기존에 받아왔던 영화 정보의 genre_ids를 통해 원하는 값을 파싱해보려고 했는데 실패했습니다.
그래서 일단 장르 데이터가 몇 개 되지 않아 딕셔너리 형태로 변수에 할당해놓고, genre_ids로 구성된 배열을 파라미터로 받는 함수를 하나 만들어서 해당하는 코드들의 장르명을 출력해주는 로직을 만들었어요. (더 좋은 방법이 있을 거 같은데..! 흐음)
영화/드라마 장르 API의 각 응답값을 보니 데이터가 많이 겹쳐있어서 genres라는 하나의 딕셔너리로 진행해보려고 합니다.
// 임시 장르 데이터
let genres: [Int: String] = [
12: "모험",
14: "판타지",
16: "애니메이션",
18: "드라마",
27: "공포",
28: "액션",
35: "코미디",
36: "역사",
37: "서부",
53: "스릴러",
80: "범죄",
99: "다큐멘터리",
878: "SF",
9648: "미스터리",
10402: "음악",
10749: "로맨스",
10751: "가족",
10752: "전쟁",
10759: "어드벤쳐",
10762: "키즈",
10763: "뉴스",
10764: "리얼리티",
10765: "SF-Fantasy",
10766: "Soap",
10767: "Talk",
10768: "전쟁",
10770: "TV영화",
]
위의 데이터 셋으로 아래 테이블뷰 셀에서만 사용할 익스텐션 안에 getGenreString 함수를 정의!
extension TrendingTableViewCell {
func convertDouble(_ double: Double) -> String {
let strDouble = String(format: "%.1f", double)
return strDouble
}
func getGenreString(list: [Int]) -> String {
var strArr: [String] = []
list.forEach { id in
strArr.append("#\(genres[id] ?? "")")
}
return strArr.joined(separator: " ")
}
}
문자열 앞에 #을 붙여줘서 장르, 태그라는 것을 시각적으로 명시할 수 있도록 하고
join() 메서드를 사용해 공백으로 연결해서 문자열로 출력한다음 장르가 들어갈 셀의 자리에 할당해주었습니다.
// configureCellData 함수
genreLabel.text = getGenreString(list: data.genre_ids)
데이터가 들어가니 꽤나 봐줄만한 화면이 탄생했습니다. 짝짝짝.
그치만 제목과 줄거리 사이 간격이 마음에 들지 않아서 이 부분을 수정하고 싶은데 레이아웃 코드를 아무리 바꿔봐도 적용이 되질 않아서 조금 더 시도해봐야겠습니다.
만들어둔 로고를 통해서 간단하게 런치스크린도 추가해주었습니다!
런치스크린이 별 거 아닌 거 같아도 잠깐동안 사용자 눈을 묶어두고 뭐라도 노출되고 있다고 알려주는 것이 큰 효과를 주는 거 같다는 생각이 듭니다.
- 스켈레톤 뷰의 cornerRadius 적용이 안 되는 이슈 (순위 레이블 부분)
- 그리고 데이터 요청 할 때 마다 스켈레톤 위치가 이동하는 이슈
- 테이블 뷰 드래그 시 스켈레 뷰가 무한 로딩되는 이슈
한정된 시간에 계속 디벨롭 시키느라 서비스적인 부분을 더 챙기지 못하고 있는데 추후 리팩토링하면서 해결해보아야겠습니다 (ㅠㅠ)