본문 바로가기

Project/MovieClip

genre_ids 의 Int 타입의 배열에 맞는 genre 찾기

📌 해결해야 할 문제

1️⃣ 영화 목록 내 genre_ids의 값을 받아옴

{
  "page": 1,
  "results": [
    {
		...
      "genre_ids": [
        27,
        53
      ],
      ...
    },

 

2️⃣ 장르의 값을 TMDB API를 통해 받아옴

{
  "genres": [
    {
      "id": 27,
      "name": "공포"
    },
		...
    },
    {
      "id": 53,
      "name": "스릴러"
    }
  ]
}

 

3️⃣ genre_Ids의 값을 TMDB API를 통해 받아온 genres에서 찾아 name을 반환

🔷  27, 53 ➡️ "공포 / 스릴러" 반환

 

 

📌 해결해야 할 문제

  1. fetchMediaData()에서 getTrendingMovies()를 호출하여 영화 목록을 가져옴.
  2. 각 영화의 genre_ids를 이용해 getMovieGenre()를 호출하고 해당 ID와 매칭되는 장르 이름을 찾음.
  3. 각 영화에 genreNames 필드를 추가하여 CollectionViewCell에서 사용할 수 있도록 함.
  4. CollectionViewCell에서 genreNames를 스릴러 / 액션 / 공포 형식으로 표시.

 

🚀 해결 방법

1️⃣ fetchMediaData()에서 getTrendingMovies()를 호출한 후, getMovieGenre()를 실행하여 장르 데이터 가져오기
2️⃣ 각 영화의 genre_ids와 getMovieGenre()에서 가져온 장르 목록을 비교하여 매칭되는 장르 이름을 저장

3️⃣ 최종적으로 MovieResult에 genreNames: [String] 추가 후, CollectionViewCell에서 활용

 

🔹 Step 1: MovieResult에 genreNames 추가

struct MovieResult: Codable {
    let id: Int
    let title: String
    let genreIds: [Int]
    let posterPath: String?
    let releaseDate: String
    let voteAverage: Double
    var genreNames: [String]? // ✅ 장르 이름을 저장하는 필드 추가
}

 

🔹 Step 2: fetchMediaData()에서 getMovieGenre() 호출하여 장르 이름 매핑

각 영화의 genre_ids와 장르 목록을 비교하여 genreNames에 저장하는 과정 추가
이제 MovieResult에 genreNames가 포함되므로, CollectionViewCell에서 사용 가능

private func fetchMediaData() {
    Task {
        do {
            // ✅ 1. 영화 목록 가져오기
            var trendingMovies = try await NetworkManager.shared.getTrendingMovies()
            
            // ✅ 2. 장르 목록 가져오기
            let genres = try await NetworkManager.shared.getMovieGenre()
            
            // ✅ 3. 각 영화의 genreIds를 genreNames로 변환
            for i in 0..<trendingMovies.count {
                let movie = trendingMovies[i]
                let matchedGenres = movie.genreIds.compactMap { genreId in
                    genres.first(where: { $0.id == genreId })?.name
                }
                trendingMovies[i].genreNames = matchedGenres // ✅ 장르 이름 저장
            }
            
            // ✅ 4. HomeViewController의 데이터 업데이트
            HomeViewController.homeSections = [
                .trendingMovies(trendingMovies)
            ]
            
            DispatchQueue.main.async {
                self.homeFeedTableView.reloadData()
            }
        } catch {
            print("Failed to fetch data: \(error)")
        }
    }
}

 

🔹 Step 3: CollectionViewCell에서 장르 표시 (/ 구분)

joined(separator: " / ")를 사용하여 장르를 "스릴러 / 액션 / 공포" 형식으로 변환
장르 정보가 없을 경우 "장르 없음"을 표시하여 UI 안정성 확보

func configureCollectionView(with movie: MovieResult) {
    titleLabel.text = movie.title
    releasedDateLabel.text = formatDateString(movie.releaseDate)
    
    let score = (movie.voteAverage)
    if score != 0 {
        scoreLabel.configure(with: Int(score) * 10)
    } else {
        scoreLabel.configure(with: 100)
    }
    
    let posterPath = movie.posterPath
    guard let url = URL(string: "https://image.tmdb.org/t/p/w500/\(posterPath)") else { return }
    posterImageView.sd_setImage(with: url, completed: nil)
    
    // ✅ 장르를 " / "로 구분하여 표시
    if let genres = movie.genreNames, !genres.isEmpty {
        genreLabel.text = genres.joined(separator: " / ") // ✅ "스릴러 / 액션 / 공포" 형식으로 표시
    } else {
        genreLabel.text = "장르 없음" // ✅ 장르 정보가 없을 경우 기본값 설정
    }
}

 

🚀 최종 정리

 

 

 


✈️ compactMap을 이용한 genreIds → genreNames 변환 이해하기

// 각 영화의 genreIds를 genreNames로 변환
for i in 0..<trendingMovies.count {
    let movie = trendingMovies[i]
    let matchedGenres = movie.genreIds.compactMap { genreId in
        genres.first(where: { $0.id == genreId })?.name
    }
    trendingMovies[i].genreNames = matchedGenres // ✅ 장르 이름 저장
}

 

위 코드의 역할

  • movie.genreIds는 해당 영화의 장르 ID 배열 (예: [27, 53])
  • genres는 모든 장르 목록 (id: name 형태의 배열)
  • compactMap {}을 이용해 해당 영화의 genre_ids를 genreNames로 변환

 

🚀 compactMap 동작 방식

1️⃣ 기존 데이터 구조

✅ trendingMovies 예제

let trendingMovies = [
    MovieResult(id: 1, title: "영화 A", genreIds: [27, 53], posterPath: "", releaseDate: "", voteAverage: 7.5),
    MovieResult(id: 2, title: "영화 B", genreIds: [28, 12], posterPath: "", releaseDate: "", voteAverage: 8.2)
]

 

✅ genres 데이터 예제 (getMovieGenre() 결과)

let genres = [
    Genre(id: 27, name: "공포"),
    Genre(id: 53, name: "스릴러"),
    Genre(id: 28, name: "액션"),
    Genre(id: 12, name: "모험")
]

 

 

2️⃣ compactMap 동작 과정

🎯 movie.genreIds에 대해 genres에서 매칭되는 name을 찾는 과정

let movie = trendingMovies[0]  // "영화 A"
let matchedGenres = movie.genreIds.compactMap { genreId in
    genres.first(where: { $0.id == genreId })?.name
}
movie.genreIds (입력) geres 에서 매칭되는 name
[27, 53] ["공포", "스릴러"]

 

 

📌 compactMap이 하는 일

✅ compactMap을 한 줄씩 설명하면:

movie.genreIds.compactMap { genreId in 
    genres.first(where: { $0.id == genreId })?.name
}

1️⃣ movie.genreIds 리스트를 순회하면서, 각 genreId에 대해
2️⃣ genres.first(where: { $0.id == genreId })을 사용하여 해당하는 장르를 찾음
3️⃣ ?.name을 통해 name만 가져옴
4️⃣ compactMap은 nil을 제거하고 유효한 값만 남김

 

🚀 compactMap을 for 문으로 풀어쓰기

var matchedGenres: [String] = []

for genreId in movie.genreIds {
    if let genre = genres.first(where: { $0.id == genreId }) {
        matchedGenres.append(genre.name)
    }
}

 

🚕 날짜형식 변경 

https://explorer89.tistory.com/320

 

날짜 형식 변환

📌 날짜 형식 변환 (2025-2-11 → 2월 11일 2025년)🔷 TMDB API를 통해 받아오는 데이터 중 released_date의 날자 형식을 변경{ "page": 1, "results": [ { ... "popularity": 396.136, "release_date": "2025-01-15", ... }, ... movie.re

explorer89.tistory.com