[뭅챠! 개발일지] DAY 4 : 인기급상승 탭 만들기, 런치스크린 추가

Deah (김준희)·2024년 6월 9일
0
post-thumbnail

안녕하세요. Deah 입니다.

오늘은 뭅챠 프로젝트에서 인기급상승 탭을 만들어보려고 해요!
바로 시작해보겠습니다. 🏃‍♀️

✨ 작업일시: 2024-06-10 (Mon)

인기급상승 탭 만들기

인기급상승 탭에서는 TMDb Trending API - All을 사용하여 영화, 드라마, 시리즈 구분없이 트렌딩이 높은 콘텐츠를 전부 노출해주려고 합니다.


TableView, TableView Cell 만들기

(매번 빌드할 때 마다 인기급상승 탭을 누르기가 귀찮아서 잠시 홈 탭으로 위치를 옮겨두었다.....)

콘텐츠가 노출될 테이블 뷰를 만들고 그 안에 셀에서 개봉 날짜, 장르, 대표 이미지, 평점, 콘텐츠 타이틀, 줄거리 등이 들어갈 수 있도록 레이아웃을 잡아주었습니다. 그리고 추후에 셀을 클릭하여 상세 화면으로 넘어갈 수 있도록 만들어줄 예정이기 때문에 클릭을 유도하는 자세히 보기와 버튼 로고도 함께 넣어주었어요.


API로 트렌딩 결과 가져오기

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)

결과물

데이터가 들어가니 꽤나 봐줄만한 화면이 탄생했습니다. 짝짝짝.
그치만 제목과 줄거리 사이 간격이 마음에 들지 않아서 이 부분을 수정하고 싶은데 레이아웃 코드를 아무리 바꿔봐도 적용이 되질 않아서 조금 더 시도해봐야겠습니다.


런치 스크린 추가하기

만들어둔 로고를 통해서 간단하게 런치스크린도 추가해주었습니다!
런치스크린이 별 거 아닌 거 같아도 잠깐동안 사용자 눈을 묶어두고 뭐라도 노출되고 있다고 알려주는 것이 큰 효과를 주는 거 같다는 생각이 듭니다.



지난 작업들에서 발견한 오류들 😦

  1. 스켈레톤 뷰의 cornerRadius 적용이 안 되는 이슈 (순위 레이블 부분)
  2. 그리고 데이터 요청 할 때 마다 스켈레톤 위치가 이동하는 이슈
  3. 테이블 뷰 드래그 시 스켈레 뷰가 무한 로딩되는 이슈
  • 첫 스켈레톤 끝나고 나오는 화면
  • 순위 랭킹 부분 cornerRadius 적용 안 되는 화면
  • 다른 날짜 검색하면 스켈레톤 위치가 달라지는 화면
  • 테이블 뷰를 드래그하면 스켈레톤 무한 로딩되는 화면

한정된 시간에 계속 디벨롭 시키느라 서비스적인 부분을 더 챙기지 못하고 있는데 추후 리팩토링하면서 해결해보아야겠습니다 (ㅠㅠ)

profile
기록 중독 개발자의 기록하는 습관

0개의 댓글