๐ ๋ฌธ์ ๋ฐฐ๊ฒฝ
ํ๋ก์ ํธ ์งํ์ค์ CollecionView๋ฅผ ์ค๋ณต์ผ๋ก ์ฌ์ฉํ๋ฉด์ ๋ฐ์ํ์์ต๋๋ค.
๊ฒ์ ํ์ด์ง | ์๋งค๋ด์ญ ๋๋ณด๊ธฐ ํ์ด์ง | ์ฐ ๋ชฉ๋ก ๋๋ณด๊ธฐ ํ์ด์ง |
![]() |
![]() |
![]() |
์ 3๊ฐ์ View๋ ๋ชจ๋ ๋ค๋ฅธ ViewController์ ๋๋ค.
๊ทธ๋ฆฌ๊ณ ์์ ์๋ ์ปฌ๋ ์ ๋ทฐ๋ ๊ฐ VC์ ์์ฑ ๋ฐ ๊ตฌ์ฑ์์ ์ ํ์ต๋๋ค.
๊ตฌํํ๊ณ ๋ณด๋, ์ปฌ๋ ์ ๋ทฐ์ ๋์์ธ์ด ๋์ผํ๋ฐ ๊ฐ VC์์ ์์ฑํ๋ค๋ณด๋ ์ค๋ณต๋๋ ๋๋์ ๋ฐ์๊ณ , VC์ ์ฝ๋์ค์ด ๊ธธ์ด์ง๋ฉด์ ๊ฐ๋ ์ฑ๋ ๋จ์ด์ง๊ฒ ๋์์ต๋๋ค.
-> ๊ทธ๋์ ์ด๋ฅผ ํ๋์ ์ปฌ๋ ์ ๋ทฐ๋ก ํ์ผ ๋ถ๋ฆฌํ์ฌ ๊ตฌ์ฑํ ๋ค์ ์ฌ์ฌ์ฉํ๋ฉด VC๊ฐ ๋ ๊ฐ๊ฒฐํด์ง๊ฒ ๋ค๊ณ ์๊ฐํ์ต๋๋ค!
๐ค ์ํฉ
์ฌ์ฌ์ฉ ํ๊ธฐ์ ์ ๊ฐ ์ปฌ๋ ์ ๋ทฐ์ ๊ณตํต์ ์ด ์๋์ง ํ์ ์ ๋จผ์ ํ์ต๋๋ค.
1. 3๊ฐ์ ์ปฌ๋ ์ ๋ทฐ ๋ชจ๋ DiffableDataSource๋ฅผ ์ฌ์ฉํ์ต๋๋ค.
2. 3๊ฐ์ ์ปฌ๋ ์ ๋ทฐ์ ์ ๋ ์ด์์ ๊ตฌ์ฑ์ด ๊ฐ์ต๋๋ค.
3. 3๊ฐ์ ์ปฌ๋ ์ ๋ทฐ ์ ์ ๋ชจ๋ ์ด๋ฏธ์ง๋ทฐ ํ๋๋ก ์ด๋ฃจ์ด์ ธ์์ต๋๋ค.
4. 3๊ฐ์ ์ปฌ๋ ์ ๋ทฐ ๋ชจ๋ APIํธ์ถ์ ํตํด ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ ๊ตฌํํ ๋ ๋ถ๊ธฐ์ ์ ๊ตฌ์ฑํ๊ธฐ ์ํด ์ฐจ์ด์ ๋ ์๊ฐํ์ต๋๋ค.
- ๊ฒ์ํ์ด์ง์ ์ฐ ๋ชฉ๋ก ๋๋ณด๊ธฐ ํ์ด์ง์ ๋ฐ์ดํฐ๋ชจ๋ธ์ MovieEntity๋ฅผ ์ฌ์ฉํฉ๋๋ค.
- ์๋งค๋ด์ญ ๋๋ณด๊ธฐ ํ์ด์ง๋ Reservation ๋ฐ์ดํฐ๋ชจ๋ธ์ ์ฌ์ฉํฉ๋๋ค.
- UseCase์ Repository๊ฐ ๊ฐ๊ฐ ์กด์ฌํฉ๋๋ค.
์ข ํฉํ์๋ฉด 3๊ฐ์ ์ปฌ๋ ์ ๋ทฐ์ UI ๊ตฌ์ฑ์ ๋ชจ๋ ๊ฐ์ง๋ง, ์ ๊ตฌ์ฑ์ ๋ฐ์ดํฐ๋ชจ๋ธ์์ ์ฐจ์ด์ ๊ณผ UseCase, Repository๊ฐ ๋ค๋ฅด๋ค๋ ์ ์ ๋๋ค.
๐ ํด๊ฒฐ ์์ด๋์ด 1: ๋ฐ์ดํฐ๋ชจ๋ธ์ ํตํฉํ์
๋ฐ์ดํฐ๋ชจ๋ธ๋ง ์ฐจ์ด๊ฐ ์์ผ๋ฏ๋ก ๋ฐ์ดํฐ๋ชจ๋ธ์ ํตํฉํ๋ ๋ฐฉ๋ฒ์ด ๋จผ์ ๋ ์ฌ๋์ต๋๋ค.
// ์ํ๊ฒ์ ํ์ด์ง, ์ฐ๋ชฉ๋ก ๋๋ณด๊ธฐ ํ์ด์ง์ ๋ฐ์ดํฐ๋ชจ๋ธ
struct MovieEntity: Hashable {
let movieID: Int // ์ํ ID
let title: String // ์ํ ์ ๋ชฉ
let genre: [String] // ์ฅ๋ฅด
let director: String // ์ํ ๊ฐ๋
let actors: [String] // ์ถ์ฐ ๋ฐฐ์ฐ (3๋ช
)
let releaseDate: String // ์ํ ๊ฐ๋ด์ผ
let runtime: Int // ์์์๊ฐ
let voteAverage: Double // ํ์ (์์์ ๋์๋ฆฌ๋ง ์ฌ์ฉ)
let voteCount: Int // ํ๊ฐ ์ธ์ ์
let overview: String // ์ค๊ฑฐ๋ฆฌ
let posterImageURL: String // ํฌ์คํฐ ์ด๋ฏธ์ง URL
let certification: String // ๊ด๋ ๋ฑ๊ธ
}
// ์๋งค๋ด์ญ ๋๋ณด๊ธฐ ๋ฐ์ดํฐ๋ชจ๋ธ
struct Reservation: Hashable {
let reservationID: String
let genre: [String]
let member: Int
let posterURL: String
let reservationTime: String
let title: String
}
๋ ๊ฐ์ ๋ฐ์ดํฐ๋ชจ๋ธ์ ํตํฉํ๊ณ DiffableDataSource๋ฅผ ์ ์ํ๋ฉด ๋๊ฒ ๋ค๋ผ๊ณ ์๊ฐ์ด ๋ค์์ง๋ง...
ํ๋ก์ ํธ์ ๊ฐ์ฅ ์์ชฝ์ ๋ ์ด์ด์ธ ๋ชจ๋ธ์ ๋ณ๊ฒฝํ๋ฉด UseCase์ Respository์ ๋ฉ์๋๋ค์ ๋ชจ๋ ๋ณ๊ฒฝํด์ผ ํ๋ ๋จ์ ์ ์๊ฒ ๋์์ต๋๋ค.
๋ํ ์ฌ์ฉํ์ง ์๋ ๋ฐ์ดํฐ๋ ์ ์ฅ๋๋ค๋ ๋จ์ ์ด ์์ต๋๋ค.
์๋ฅผ ๋ค์ด ์๋งค๋ด์ญ์์๋ overview(์ค๊ฑฐ๋ฆฌ), certification(๊ด๋๋ฑ๊ธ) ํญ๋ชฉ๋ค์ ํ์๊ฐ ์์ด์ ๋ฐ์ดํฐ๊ณต๊ฐ์ ์ฐจ์งํ๊ฒ ๋ฉ๋๋ค.
์๋งค๋ด์ญ ๋ฐ์ดํฐ๊ฐ ํ์ด์ด๋ฒ ์ด์ค์ ์ ์ฅ๋ ๋ชจ์ต | ์ฐ ๋ชฉ๋ก ๋ฐ์ดํฐ๊ฐ ํ์ด์ด๋ฒ ์ด์ค์ ์ ์ฅ๋ ๋ชจ์ต |
![]() |
![]() |
ํด๋น ๋ฐฉ๋ฒ์ ํ๋ฆฌ๊ณ ์๋์ด ์๋๋ ์์ด๋์ด๋ ์๋์ง๋ง,
๋ง์ ์ฝ๋๋ฅผ ๋ณ๊ฒฝํด์ผํ๋ค๋ ์ ๊ณผ ๋ฐ์ดํฐ ๊ณต๊ฐ์ ์ ์ฝํ๊ธฐ ์ํ์ฌ ํด๋น ์์ด๋์ด๋ฅผ ์ฌ์ฉํ์ง ์์์ต๋๋ค.
๐ ํด๊ฒฐ ์์ด๋์ด 2: ๋ค์ํ ๋ฐ์ดํฐ๋ชจ๋ธ์ ๋ฐ๋๋ก DiffableDataSource๋ฅผ ์ ์ํ์
์ด ๊ธ์ ํต์ฌ๋ด์ฉ์ด ์ฌ๊ธฐ์ ๋์ค๋๋ฐ์.
DiffableDataSource๋ฅผ ์ ์ํ ๋ ๋ค์ํ ๋ฐ์ดํฐ๋ชจ๋ธ์ ๋ฐ๋๋กํ์ฌ ์ปฌ๋ ์ ๋ทฐ์ ์ฌ์ฌ์ฉ์ฑ์ ๋๋ฆฌ๋ ๋ฐฉ๋ฒ์ ๋๋ค.
์ด๋ ๊ฐ VC์ UseCase์ Repository๋ฅผ ๊ทธ๋๋ก ์ ์งํ๋ฉด์ ๋ฐ์ดํฐ๋ชจ๋ธ๋ง ์ ์ฐํ๊ฒ ๋ฐ๋๋ก ํ์ฌ 1๋ฒ์ ์์ด๋์ด๋ณด๋ค ์ ๊ฒ ์ฝ๋๋ฅผ ์์ ํ ์ ์๊ณ , ์ด๋ฏธ ๊ตฌํ๋ ๋ฐ์ดํฐ๋ชจ๋ธ์ ์ฌ์ฉํ๋ฏ๋ก ํ์ํ ๋ฐ์ดํฐ๋ง ์ ์ฅํ๊ณ ์ฌ์ฉํ๋๋ก ๊ตฌํํ ์ ์๋ค๊ณ ํ๋จํ์ต๋๋ค.
// ๋ฐ์ดํฐ๋ชจ๋ธ์ ์ด๊ฑฐํ์ผ๋ก ๊ตฌํ
enum ItemWrapper: Hashable {
case movieEntity(MovieEntity)
case reservationEntity(Reservation)
}
typealias DataSource = UICollectionViewDiffableDataSource<Section, ItemWrapper>
typealias SnapShot = NSDiffableDataSourceSnapshot<Section, ItemWrapper>
// ์
๋ฑ๋ก ์ ์
let cellRegistration = UICollectionView.CellRegistration<MovieItemCollectionViewCell, [ItemWrapper]> { cell,indexPath,itemIdentifier in }
// ์
๊ตฌ์ฑํ ๋ ๋ถ๊ธฐ์ ์ ์์ฑํ์ฌ ํด๋น ์
์ configureํ๋๋ก ์์
movieItemCollectionDataSource = DataSource(collectionView: self) { collectionView, indexPath, item in
let cell = collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: [item])
switch item {
case .movieEntity(let movieEntity):
cell.configure(model: movieEntity)
case .reservationEntity(let reservationEntity):
cell.configure(model: reservationEntity)
}
return cell
}
// Item ์ค๋
์ท ์์ฑ
private func makeSnapShot(item: [CellConfigurable]) -> SnapShot {
var snapshot = SnapShot()
snapshot.appendSections([.main])
if item is [MovieEntity] {
snapshot.appendItems(item.map{ItemWrapper.movieEntity($0 as! MovieEntity)})
}
if item is [Reservation] {
snapshot.appendItems(item.map{ItemWrapper.reservationEntity($0 as! Reservation)})
}
return snapshot
}
๋ํ ์ปค์คํ ์ ์ configure๋ฉ์๋์์ ๋งค๊ฐ๋ณ์๋ก ๊ฐ ๋ฐ์ดํฐ๋ชจ๋ธ์ ๋ฐ๋๊ฑธ ์ฌ๋ฌ๊ฐ์ ๋ฐ์ดํฐ๋ชจ๋ธ์ ๋ฐ๋๋ก ํ๊ธฐ ์ํด ํ๋กํ ์ฝ์ ์์ฑํ๊ณ ๋ฐ์ดํฐ๋ชจ๋ธ๋ค์ด ์ฑํํ๊ฒ ์์ ํ์์ต๋๋ค.
๋งค๊ฐ๋ณ์์๋ ํด๋น ํ๋กํ ์ฝ์ ์ฑํํ๋ ๋ฐ์ดํฐ๋ชจ๋ธ์ด ๋ค์ด์ค๋๋ก ์์ ํ์์ต๋๋ค.
// ๋ฐ์ดํฐ๋ชจ๋ธ์ ๊ณตํต ํ์
์ ๋งค๊ฐ๋ณ์๋ก ์ ๋ฌํ๊ธฐ ์ํด ํ๋กํ ์ฝ ์์ฑ
protocol CellConfigurable { }
// ํ๋กํ ์ฝ ์ฑํ
extension MovieEntity: CellConfigurable { }
extension Reservation: CellConfigurable { }
// CustomCell์ configure ๋ฉ์๋
func configure(model: CellConfigurable) {
if let model = model as? MovieEntity {
// ์๋งค๋ด์ญ UI ๊ตฌ์ฑ
}
if let model = model as? Reservation {
// ์ฐ๋ชฉ๋ก UI ๊ตฌ์ฑ
}
}
'iOS' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[ํธ๋ฌ๋ธ ์ํ ] CoreData์ Entity Attribute์ ํ์ ์ ๋ณ๊ฒฝํ ๊ฒฝ์ฐ (0) | 2025.04.23 |
---|---|
๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ํ์ธ์ ์ํ vmmap (1) | 2025.03.18 |
UICollectionViewLayout๊ณผ UICollectionViewFlowLayout (0) | 2025.03.03 |
UIBeizerPath (0) | 2025.02.26 |
NotificationCenter (0) | 2025.02.20 |