📌 테이블 뷰 안에 컬렉션 뷰를 넣고, 섹션별로 다른 데이터 모델을 사용하는 경우
테이블 뷰의 각 섹션에서 서로 다른 API 데이터를 받아와 컬렉션 뷰 셀에 전달해야 한다면, 각 섹션에 맞는 데이터 모델을 관리할 방법이 필요
🚀 해결 방법: Enum + Associated Value 사용
🔹 각 섹션에서 다른 데이터 모델을 사용할 때, Enum을 활용하면 쉽게 구분 가능
🔹 각 섹션별 데이터를 Enum의 case에 저장하여 switch 문으로 분기 처리
// 1. 각 섹션별 데이터 모델 정의
struct TrendingMovie {
let title: String
let posterURL: String
}
struct PopularTVShow {
let name: String
let thumbnailURL: String
}
struct UpcomingMovie {
let title: String
let releaseDate: String
}
// 2. 섹션 타입을 Enum으로 정의
enum HomeSection {
case trendingMovies([TrendingMovie])
case popularTVShows([PopularTVShow])
case upcomingMovies([UpcomingMovie])
}
📌 테이블 뷰에서 Enum을 사용하여 데이터 관리
class HomeViewController: UIViewController {
private let homeFeedTableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .grouped)
tableView.separatorStyle = .none
return tableView
}()
// 3. 테이블의 섹션별 데이터 저장
private var sections: [HomeSection] = []
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(homeFeedTableView)
setupTableView()
fetchData() // ✅ API 데이터 가져오기
}
private func setupTableView() {
homeFeedTableView.delegate = self
homeFeedTableView.dataSource = self
homeFeedTableView.register(HomeFeedTableViewCell.self, forCellReuseIdentifier: "HomeFeedTableViewCell")
}
// 4. API에서 데이터를 받아와 sections에 저장
private func fetchData() {
Task {
do {
let trendingMovies = try await NetworkManager.shared.getTrendingMovies()
let popularTVShows = try await NetworkManager.shared.getPopularTVShows()
let upcomingMovies = try await NetworkManager.shared.getUpcomingMovies()
self.sections = [
.trendingMovies(trendingMovies),
.popularTVShows(popularTVShows),
.upcomingMovies(upcomingMovies)
]
DispatchQueue.main.async {
self.homeFeedTableView.reloadData()
}
} catch {
print("Failed to fetch data: \(error)")
}
}
}
}
📌 테이블 뷰에서 Enum을 사용하여 섹션별 데이터 제공
extension HomeViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1 // ✅ 각 섹션에 컬렉션뷰 1개만 존재
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "HomeFeedTableViewCell", for: indexPath) as? HomeFeedTableViewCell else {
return UITableViewCell()
}
let sectionData = sections[indexPath.section]
cell.configure(with: sectionData) // ✅ 섹션별 데이터를 전달
return cell
}
}
📌 컬렉션 뷰에서 Enum을 사용하여 데이터 바인딩
class HomeFeedTableViewCell: UITableViewCell {
private let homeCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 10
layout.itemSize = CGSize(width: 180, height: 250)
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.showsHorizontalScrollIndicator = false
return collectionView
}()
private var items: [Any] = [] // ✅ 섹션별로 다른 데이터 저장
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(homeCollectionView)
homeCollectionView.delegate = self
homeCollectionView.dataSource = self
homeCollectionView.register(MovieCollectionViewCell.self, forCellWithReuseIdentifier: "MovieCollectionViewCell")
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// ✅ 데이터를 설정하는 함수
func configure(with section: HomeSection) {
switch section {
case .trendingMovies(let movies):
self.items = movies
case .popularTVShows(let shows):
self.items = shows
case .upcomingMovies(let movies):
self.items = movies
}
homeCollectionView.reloadData()
}
}
📌 컬렉션 뷰 데이터 제공
extension HomeFeedTableViewCell: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return items.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MovieCollectionViewCell", for: indexPath) as? MovieCollectionViewCell else {
return UICollectionViewCell()
}
if let movie = items[indexPath.item] as? TrendingMovie {
cell.configure(with: movie.title, imageURL: movie.posterURL)
} else if let tvShow = items[indexPath.item] as? PopularTVShow {
cell.configure(with: tvShow.name, imageURL: tvShow.thumbnailURL)
} else if let upcoming = items[indexPath.item] as? UpcomingMovie {
cell.configure(with: upcoming.title, imageURL: "placeholder_url")
}
return cell
}
}
'Project > MovieClip' 카테고리의 다른 글
영어 장르 이름을 한글로 표시하기 (0) | 2025.02.07 |
---|---|
genre_ids 의 Int 타입의 배열에 맞는 genre 찾기 (0) | 2025.02.06 |
에러 발생 - 데이터 모델 누락 (0) | 2025.02.05 |
TMDB API 데이터를 가져오는 방식 - async / await 방식 채택 (0) | 2025.02.05 |
테이블과 테이블 헤더뷰 제약조건 구현하기, 글자색 따로 주기 (0) | 2025.02.05 |