1. 접근방식 검토
✅ 적절한 접근 방식
- 영화/TV의 비디오 정보를 가져와서 헤더뷰 및 상세 페이지에서 활용
- 공식 트레일러(Official Trailer) 또는 티저(Official Tease)를 우선적으로 가져오기 → Trailer 버튼을 통해 WebView에서 재생
- 나머지 비디오 정보는 테이블뷰의 미디어 섹션에서 컬렉션뷰로 표시 → 사용자가 더 많은 미디어 탐색 가능 (추후)
2. 개선해야 할 부분
1️⃣ compactMap을 사용하여 원하는 key 값 가져오기
2️⃣ 비디오 정보가 없는 경우 예외 처리 (default 값 또는 nil 체크) (중요)
3️⃣ 추가적인 영상 정보를 미디어 섹션(컬렉션뷰)으로 전달하도록 설계 (나중에)
✅ 업데이트된 fetchContentDetail 메서드
HomeViewController 클래스 내에서 실행되는 fetchContentDetail 내에 영화_id 또는 tv_id를 통해 비디오 정보를 받아오는 로직 추가
private func fetchContentDetail() {
Task {
do {
var fetchedDetail: ContentDetail?
var fetchedGenres: [String] = [] // ✅ 장르 저장 변수
var videoPath: String? = nil // ✅ 유튜브 영상 URL 저장
var allVideoResults: [VideoInfoResult] = [] // ✅ 전체 비디오 데이터 저장
switch contentType {
case .movie:
let movieDetail = try await NetworkManager.shared.getMovieDetailInfo(movieID: contentID)
fetchedDetail = .movie(movieDetail)
fetchedGenres = getGenresFromHomeSection(for: contentID)
// ✅ 영화 비디오 정보 가져오기
let videoInfo = try await NetworkManager.shared.getMovieVideoInfo(contentID: contentID)
// ✅ "Official Trailer" 또는 "Official Tease"에 해당하는 key 가져오기
videoPath = videoInfo.results
.first(where: { $0.name == "Official Trailer" || $0.name == "Official Tease" })?.key
// ✅ 전체 비디오 정보 저장
allVideoResults = videoInfo.results
case .tv:
let tvDetail = try await NetworkManager.shared.getTVDetailInfo(tvID: contentID)
fetchedDetail = .tv(tvDetail)
fetchedGenres = getGenresFromHomeSection(for: contentID)
// ✅ TV 비디오 정보 가져오기
let videoInfo = try await NetworkManager.shared.getTVVideoInfo(contentID: contentID)
// ✅ "Official Trailer" 또는 "Official Tease"에 해당하는 key 가져오기
videoPath = videoInfo.results
.first(where: { $0.name == "Official Trailer" || $0.name == "Official Tease" })?.key
// ✅ 전체 비디오 정보 저장
allVideoResults = videoInfo.results
case .people:
let peopleDetail = try await NetworkManager.shared.getPeopleDetailInfo(peopleID: contentID)
fetchedDetail = .people(peopleDetail)
}
DispatchQueue.main.async {
guard let contentDetail = fetchedDetail else { return }
self.contentDetail = contentDetail
self.detailTableHeaderView() // ✅ 헤더뷰 설정
switch contentDetail {
case .movie(let movieDetail):
self.detailHeaderView?.configure(movieDetail, genres: fetchedGenres, videoPath: videoPath)
case .tv(let tvDetail):
self.detailHeaderView?.configure(tvDetail, genres: fetchedGenres, videoPath: videoPath)
case .people(let peopleDetail):
self.detailHeaderView?.configure(peopleDetail)
}
// ✅ 테이블뷰 미디어 섹션을 위한 전체 비디오 데이터 전달
self.allVideos = allVideoResults
self.detailTableView.reloadData()
}
} catch {
print("❌ 데이터 로드 실패: \(error)")
}
}
}
✅ 비디오 데이터 활용 (DetailHeaderView)
1️⃣ DetailHeaderView에서 버튼 액션을 DetailViewController로 전달
// DetailHeaderView.swift
import UIKit
// ✅ Protocol 생성 (데이터 전달_)
protocol DetailHeaderViewDelegate: AnyObject {
func didTapTrailerButton(videoKey: String)
}
class DetailHeaderView: UIView {
// ✅ 대리자 선언
weak var delegate: DetailHeaderViewDelegate?
private var trailerVideoKey: String?
private let trailerButton: UIButton = {
let button = UIButton()
button.setTitle("▶️ 예고편 보기", for: .normal)
button.backgroundColor = .red
button.addTarget(self, action: #selector(didTapTrailerButton), for: .touchUpInside)
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(trailerButton)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configure(_ movie: MovieDetailInfoWelcome, genres: [String], videoPath: String?) {
trailerVideoKey = videoPath
trailerButton.isHidden = (videoPath == nil) // ✅ 영상 없으면 버튼 숨기기
}
@objc private func didTapTrailerButton() {
guard let videoKey = trailerVideoKey else { return }
delegate?.didTapTrailerButton(videoKey: videoKey) // ✅ 뷰컨트롤러로 전달
}
}
✅ YouTube WebView (트레일러 재생)
// TrailerViewController.swift
import UIKit
import WebKit
class TrailerViewController: UIViewController {
private let videoKey: String
init(videoKey: String) {
self.videoKey = videoKey
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private let webView: WKWebView = {
let webView = WKWebView()
return webView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(webView)
webView.frame = view.bounds
if let url = URL(string: "https://www.youtube.com/watch?v=\(videoKey)") {
webView.load(URLRequest(url: url))
}
}
}
✅ HomeViewController 내에 delegate 설정
private func detailTableHeaderView() {
detailHeaderView = DetailHeaderView(frame: CGRect(x: 0, y: 0, width: view.bounds.width, height: 350))
detailHeaderView?.delegate = self // ✅ 여기서 delegate 설정
detailTableView.tableHeaderView = detailHeaderView
}
// Protocol 채택: didTapTrailerButton 메서드 구체화
extension DetailViewController: DetailHeaderViewDelegate {
func didTapTrailerButton(videoKey: String) {
let trailerVC = TrailerViewController(videoKey: videoKey)
present(trailerVC, animated: true)
}
}
✅ 🚀 최종 동작 흐름
1️⃣ DetailViewController에서 API 요청 → DetailHeaderView에 비디오 데이터 전달
2️⃣ 트레일러 버튼 클릭 시, DetailHeaderView가 DetailViewController로 이벤트 전달
3️⃣ DetailViewController가 TrailerViewController를 present하여 WebView에서 유튜브 영상 재생
🚗 개선
✅ "Official Trailer" 또는 "Official Teaser"가 있으면 그 key를 사용하고, 없으면 key가 있는 첫 번째 항목을 선택하는 방법"
🔹 해결 방법
first(where:)를 사용하면 특정 조건에 맞는 첫 번째 요소만 가져오기 때문에, 조건을 여러 개 설정하고 fallback(대체값)을 추가해야 해.
📌 우선순위 설정:
- "Official Trailer" 또는 "Official Tease"가 있으면 해당 key 사용
- 만약 없으면 key가 있는 첫 번째 요소를 사용
- 그래도 없으면 nil 반환
🔹수정 코드
// ✅ "Official Trailer" 또는 "Official Tease"가 있으면 그 key를 사용하고, 없으면 key가 있는 첫 번째 항목을 선택
videoPath = videoInfo.results.first(where: {
$0.name == "Official Trailer" || $0.name == "Official Teaser"
})?.key ?? videoInfo.results.first(where: {
$0.key != nil
})?.key
📌 설명
- first(where:)를 사용해서 "Official Trailer" 또는 "Official Teaser"를 찾음.
- 만약 위에서 찾지 못했다면, key가 nil이 아닌 첫 번째 요소를 찾음.
- 이렇게 하면 트레일러가 없더라도 다른 영상이 있으면 그 key를 사용할 수 있음.
🔹 전체 적용 코드
case .movie:
let movieDetail = try await NetworkManager.shared.getMovieDetailInfo(movieID: contentID)
fetchedDetail = .movie(movieDetail)
fetchedGenres = getGenresFromHomeSection(for: contentID)
// ✅ 영화 비디오 정보 가져오기
let videoInfo = try await NetworkManager.shared.getVideoInfo(contentID: contentID)
// ✅ "Official Trailer" 또는 "Official Teaser"가 있으면 그 key를 사용하고, 없으면 key가 있는 첫 번째 항목을 선택
videoPath = videoInfo.results.first(where: {
$0.name == "Official Trailer" || $0.name == "Official Teaser"
})?.key ?? videoInfo.results.first(where: {
$0.key != nil
})?.key
allVideoResults = videoInfo.results
'Project > MovieClip' 카테고리의 다른 글
헷갈리기 쉬운 주요 출연진 정보를 받아오는 로직 (0) | 2025.02.10 |
---|---|
테이블의 rowheight을 동적으로 할 때 주의할 점 (0) | 2025.02.10 |
✅ UIScrollView 안에 UITableView를 넣는 것이 올바른가? (상세페이지 구현) (0) | 2025.02.09 |
셀 재사용으로 인한 이전 데이터 표시되는 문제 (0) | 2025.02.08 |
상세페이지로 넘어가기 (문제 해결, 데이터 전달 방법 비교) (0) | 2025.02.08 |