์ต์ ์ํ์ ์์ ๋ฐ ์ฅ๋ฅด ๋ณ ์ํ๋ฅผ ์ฐพ์๋ณผ ์ ์๋ ๋ฐ์ค์คํผ์ค ์ฑ์ ๋๋ค
โบ๏ธ
๊ฐ๋ฐ ์ธ์ | ์ ์ ๊ธฐ๊ฐ |
---|---|
1์ธ ๊ฐ๋ฐ | 5.16 ~ 5.30(2์ฃผ) |
ํํ๋ฉด ๋ทฐ | ๋ํ ์ผ ๋ทฐ | ์ฅ๋ฅด ๋ทฐ |
---|---|---|
์์น ๋ทฐ | ์ฆ๊ฒจ์ฐพ๊ธฐ ๋ทฐ |
---|---|
Autolayout |
---|
Snapkit |
- Autolayout์ ์ก์์ค ๋ ์ฌ์ฉ๋๋ boilerplate ์ฝ๋๋ฅผ ์ค์ด๊ธฐ์ํ์ฌ Snapkit ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํ์ฉํ์ด์.
- ๐ฅ ํ๋์ datasource๋ฅผ ํ์ฉํ์ฌ ์๋ก ๋ค๋ฅธ API ๋ฐ์ดํฐ ๋ชจ๋ธ ์ฒ๋ฆฌํ๊ธฐ
- ๐ฅ Collection View ๋ ์ด์์ ์ง๊ธฐ
- ๐ฅ ๊ฐ๋ณ์ ์ธ cell ๊ตฌํํ๊ธฐ
- ๐ฅ ๋ฌด๊ฑฐ์์ง view controller ๋์ด๋ด๊ธฐ
- ๐ฅ View controller์ ์ํ ์ฐธ์กฐ ๋ฌธ์
๐ Please Open
DiffableDatasource
๋ฅผ ์ฌ์ฉํ ์ด์
- Home scene ์ ์๋จ section์ ์ธ๊ธฐ ์๋ ์ํ ๋ณด์ฌ์ฃผ๊ณ , ํ๋จ section์ ์ ์ฒด ์ํ๋ฅผ ์ฅ๋ฅด ๋ณ๋ก ๋๋ด์ด์.
- ์๋จ section(์ดํ rank section)์ ๊ฒฝ์ฐ, header์ ์ธ๊ธฐ ์์น ์, ์ํ ๊ฐ๋ด ์ ๋ฒํผ์ ๋์ด ํด๋น ๊ธฐ์ค์ ํตํ์ฌ ์ํ๋ค์ด sorting์ด ๋๋๋ก ๊ตฌํ์ ํด๋ณด์์ด์. ๋ํ, ํ๋จ์ ์ฅ๋ฅด๋ณ ์ํ section(์ดํ genre section)์ ๊ฒฝ์ฐ์๋, ๋๋ณด๊ธฐ ๋ฒํผ์ ๋๋ฌ ์จ๊ฒจ์ง ๋๋จธ์ง ์ ๋ค์ ๋ณด์ฌ์ฃผ๋๋ก ๊ตฌํ์ ํด๋ณด์์ด์.
- ๊ธฐ์กด์๋ reloadData๋ฅผ ํ์ฉํ์ฌ controller๊ฐ ๋ณ๊ฒฝ์ฌํญ์ UI์๊ฒ ์๋ ค์ฃผ๋ ๋๊ธฐํ ์์ ์ ํด์ฃผ์์ด์. ๊ทธ๋ฌ๋, ํด๋น ํ๋ก์ ํธ์์๋ ๋ ์ด์์ UI๊ฐ ๋น๋ฒํ๊ฒ ๋ณ๊ฒฝ๋๋ฉฐ ์ ๋๋ฉ์ด์ ์ด ์๋์ผ๋ก ์ ์ฉ๋์ง ์๋ reloadData๋ฅผ ํ์ฉํ์ฌ ๋๊ธฐํ๋ฅผ ์งํํ ๊ฒฝ์ฐ, ์ฌ์ฉ์ UX ๊ฒฝํ์ด ๋จ์ด์ง ์ ์๋ค๊ณ ํ๋จ์ด ๋ค์๊ธฐ์ DiffableDatasource๋ฅผ ํ์ฉํ์ด์.
Diffabledatasource์ ๊ฒฝ์ฐ, ํ๋์ collection view์์ ํ๋์ item identifier ํ์ ์ ๊ฐ์ง๊ณ ์์ด์. ๊ฐ๊ฐ์ ์น์ ์ ์๋ก ๋ค๋ฅธ API ํธ์ถ์ ํ๋ฏ๋ก, ๋ค๋ฅธ ๋ฐ์ดํฐ ๋ชจ๋ธ์ ๊ฐ์ง๊ณ ํ๋์ datasource item identifier ํ์ ์ ๋ง๋ค์ด์ค์ผํ์ด์. ๋ค์์ ์ ๊ฐ ํด๋น ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์ ๊ณ ๋ฏผํ๋ ๊ณผ์ ์ด์์.
- ์ ๋ ๋ API๋ฅผ ํตํด์ ๋ฐ์์จ ๋ฐ์ดํฐ ๋ชจ๋ธ์ ํฉ์น Movie ํ์ ์ ๋ง๋ค์ด์ item identifier ํ์ ์ผ๋ก ํ์ฉํ๋ ค๊ณ ํ์ด์.
- ๊ทธ๋ฆฌ๊ณ , ์๋์ ๊ฐ์ด ์๋ก ๋ค๋ฅธ section์ items๋ค์ appendํ๋๋ก ๋ก์ง์ ๊ตฌํํ์ด์.
// ๐ฟ in HomeViewController
private var datasource: DataSource?
// โ
Rank Section
private var movies = [Movie]() {
didSet {
applySnapShot()
}
}
// โ
genre Section
private var genres = [Movie]() {
didSet {
applySnapShot()
}
}
private func applySnapShot() {
var snapShot = SnapShot()
snapShot.appendSections([.rank])
snapShot.appendItems(movies)
snapShot.appendSections([.genre])
snapShot.appendItems(genres)
self.datasource?.apply(snapShot)
}
}
- ์ด๋ ๊ฒ ๊ตฌํํ ๊ฒฝ์ฐ, ์ํ๋ ๋๋ก ์๋ก ๋ค๋ฅธ ํ์ ์ ๋ฐ์ดํฐ ๋ชจ๋ธ์ ํ๋์ diffable datasource๋ฅผ ํ์ฉํ์ฌ collection view์ ๊ตฌํํ ์ ์์์ด์.
- ๊ทธ๋ฌ๋, ๋์ ํฉ์น model(item identifier)์ optional์ด ๋๋ฌดํ๊ณ , ๋ถํ์ํ ์ฝ๋๋ค์ด ๋ง์ด ์๊ธฐ๊ฒ ๋์์ด์.
- ๋ด๊ณ ์ถ์ ๋ฐ์ดํฐ ํ์
์
ItemIdenfiable
ํ๋กํ ์ฝ์ ์ฑํํ๋๋ก ํด์.
// ๐ฅ ItemIdenfiable ํ๋กํ ์ฝ ์ ์
protocol ItemIdenfiable {
var identity: UUID { get set }
}
// ๐ฅ ํ๋กํ ์ฝ์ ์ฑํํ MovieGenre ํ์
์ ์
struct MovieGenre: ItemIdenfiable {
var identity = UUID()
...
}
// ๐ฅ ํ๋กํ ์ฝ์ ์ฑํํ Movie ํ์
์ ์
struct Movie: ItemIdenfiable {
var identity = UUID()
...
}
ItemIdenfiable
ํ ํ๋กํผํฐ๋ฅผ ๊ฐ์ง๊ณ ์๋ ItemType ๊ตฌ์กฐ์ฒด๋ฅผ ์ ์ํ์ฌ diffable datasource์ item identifier ํ์ ์ผ๋ก ํ์ฉํ๋ ๋ฐฉ์์ด์์.
// ๐ฅ Item identifier ํ์
๊ตฌํ
private struct ItemType: Hashable {
var item: any ItemIdenfiable
static func == (lhs: MovieHomeViewController.ItemType, rhs: MovieHomeViewController.ItemType) -> Bool {
return lhs.item.identity == rhs.item.identity
}
func hash(into hasher: inout Hasher) {
hasher.combine(item.identity)
}
}
private typealias DataSource = UICollectionViewDiffableDataSource<Section, ItemType>
- ์๋์ ๊ฐ์ด ItemType์ผ๋ก
ItemIdenfiable
์ ์ฑํํ ๋ฐ์ดํฐ ๋ชจ๋ธ์ ๊ฐ์ธ์ items๋ก appendํด์.
private func applySnapShot() {
var snapShot = SnapShot()
snapShot.appendSections(Section.allCases)
var rankMovies = movieHomeController.movies
let movieItems = rankMovies.map { ItemType(item:$0) }
snapShot.appendItems(movieItems, toSection: .rank)
var allGenres = movieHomeController.genres
let genreItems = allGenres.map { ItemType(item: $0) }
snapShot.appendItems(genreItems, toSection: .genre)
datasource?.apply(snapShot)
}
- ๊ทธ๋ฌ๋ ์ค, ์ ํ ๊ณต์๋ฌธ์ ์ ์์ ์ฝ๋์์ ์๋ก ๋ค๋ฅธ item๋ค์ ํ๋์ ํ์ ์ผ๋ก ๊ฐ์ธ์ ํ์ฉํ๋ ์ฝ๋๋ฅผ ๋ณด์์ด์
- ์ด๋ฅผ ์ฐธ๊ณ ํ์ฌ ์ ๋ ํ๋์ enum ํ์ ์ผ๋ก ์๋ก ๋ค๋ฅธ section์ ํ์ฉ๋๋ ๋ฐ์ดํฐ ๋ชจ๋ธ์ ๋ฌถ๊ณ , ๊ฐ๊ฐ์ ๋ชจ๋ธ์ enum์ ์ฐ๊ด ๊ฐ์ผ๋ก ๋ฃ์ด์ฃผ๋ ๋ฐฉ๋ฒ์ผ๋ก ๊ตฌํํด๋ณด๊ธฐ๋ก ํ์ด์.
private struct SidebarItem: Hashable {
let title: String
let type: SidebarItemType
enum SidebarItemType {
case standard, collection, expandableHeader
}
}
private func createSnapshotOfRecipeCollections() -> NSDiffableDataSourceSectionSnapshot<SidebarItem> {
let items = recipeSplitViewController.recipeCollections.map { SidebarItem(title: $0, type: .collection) }
return createSidebarItemSnapshot(.recipeCollectionItems, items: items)
}
- ์ฐ๊ด ๊ฐ์ผ๋ก ๋ด๊ฐ ๋ด๊ณ ์ถ์ ๋ฐ์ดํฐ ๋ชจ๋ธ ํ์
์ ๊ฐ์ง ์ ์๋
item
์ด๊ฑฐํ ํ์ ์ ์ํด์.
private enum Item: Hashable {
case rank(Movie)
case gerne(MovieGenre)
}
private typealias DataSource = UICollectionViewDiffableDataSource<Section, Item>
- ์๋์ ๊ฐ์ด enum์ ์ฐ๊ด ๊ฐ์ผ๋ก ๋ฐ์ดํฐ ๋ชจ๋ธ์ ๋ฃ์ด์ item identifier ํ์ ์ ๊ตฌํํด์.
private func applySnapShot() {
var snapShot = SnapShot()
snapShot.appendSections(Section.allCases)
var rankMovies = movieHomeController.movies
// ๐ฅ ์ฐ๊ด ๊ฐ ๋ฃ์ด์ฃผ๊ธฐ
let movieItems = rankMovies.map { Item.rank($0) }
var allGenres = movieHomeController.genres
snapShot.appendItems(movieItems, toSection: .rank)
// ๐ฅ ์ฐ๊ด ๊ฐ ๋ฃ์ด์ฃผ๊ธฐ
let genreItems = allGenres.map { Item.gerne($0) }
snapShot.appendItems(genreItems, toSection: .genre)
datasource?.apply(snapShot)
}
๐ฌ 2,3๋ฒ ๋ฐฉ๋ฒ ๋ชจ๋ ๋ค, Hashable์ ๋ง์กฑํ๋ ํ์ ์ผ๋ก ๋ฃ๊ณ ์ถ์ ๋ฐ์ดํฐ ๋ชจ๋ธ์ ๋ํํ๋ค๋ ๊ณตํต์ ์ด ์์ด์.
- 2๋ฒ์งธ protocol ๋ฐฉ๋ฒ์ ๊ฒฝ์ฐ, DIP ๋ฒ์น์ ๋ง์กฑํ์ฌ
ItemIdentifiable
ํ๋กํ ์ฝ์ ์ฑํํ ์ด๋ค ๋ชจ๋ธ์ด๋ item identifier๊ฐ ๋ ์ ์์ผ๋ฏ๋ก ์์ฝ๊ฒ section์ด ์ถ๊ฐ๋ ๋๋ง๋ค item ํ์ ์ ์ถ๊ฐํ ์ ์์ด์. - 3๋ฒ์งธ enum์ ์ฐ๊ด ๊ฐ์ ํ์ฉํ ๊ฒฝ์ฐ, ์น์ ์ด ์ถ๊ฐ๋ ๊ฒฝ์ฐ, case๋ง ์ถ๊ฐํด์ฃผ๋ฉด ์์ฝ๊ฒ item ํ์ ์ ์ถ๊ฐํ ์ ์์ด์.
โก๏ธ ๋ ๊ฐ์ง ๋ฐฉ๋ฒ ๋ค ์ฅ์ ์ด ์กด์ฌํ์ง๋ง, enum์ ํ์ฉํ ๋ฐฉ๋ฒ์ด case๋ฅผ ํตํ์ฌ ํ๋์ ํ์ฉ๋ item type์ด ๋ณด์ธ๋ค๋ ์ ๊ณผ, cell ์ฌ์ฌ์ฉ ์ ๋ถ๊ธฐ์ฒ๋ฆฌ์์ ๋ถํ์ํ default ์ผ์ด์ค๋ฅผ ์จ์ฃผ์ง ์์๋ ๋๋ค๋ ์ ์์ ํด๋น ํ๋ก์ ํธ์์๋ enum ์ผ์ด์ค๋ฅผ ํ์ฉํ์ฌ item identifier ํ์ ์ ๊ตฌํํ์ด์.
๐ Please Open
- ์ ๋ ์๋จ์ ์ํ ์ ๋ณด๋ฅผ ๋์ด์ฃผ๋ ๋ถ๋ถ(์ดํ detail view)๊ณผ ํ๋จ์ ์ํ์ธ ์ ๋ณด๋ฅผ ๋ณด์ฌ์ฃผ๋ ๋ถ๋ถ(์ดํ credits view)์ compositonal layout์ผ๋ก ๊ตฌํํ๊ธฐ ์ํ์ฌ ๋ค ๊ฐ์ง ๋ฐฉ๋ฒ์ ๊ณ ๋ฏผํด๋ณด์์ด์.
- Detail view ์๋ collection view ๋ฃ๊ธฐ
- Header View๋ฅผ ํ์ฉํด์ Detail View๋ฅผ ๊ตฌํํ๊ธฐ
- Scroll view์์ detail view์ collection view ๋ฃ๊ธฐ
- Detail view๋ฅผ ์ฒซ ๋ฒ์งธ section์, credit view๋ฅผ ๋ ๋ฒ์งธ section์ผ๋ก ๋ฃ๊ธฐ
- ๊ฐ์ฅ ๋จผ์ ์๊ฐํ๋ ๋ฐฉ๋ฒ์ด์๋๋ฐ, ์ด๋ ๊ฒ ๊ตฌํํ ๊ฒฝ์ฐ, ์ ์ฒด ํ๋ฉด์ด scroll ๋์ง ์๊ณ credit view๋ง ๊ฐ๋ก๋ก ์คํฌ๋กค๋๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ด์. ๋ฐ๋ผ์ ๋ ๋ฒ์งธ ๋ฐฉ๋ฒ์ ์๊ฐํ๊ฒ๋์์ด์.
- ์ ์ฒด๋ฅผ ํ๋์ section์ผ๋ก ๊ตฌํํ์ฌ Detail view๋ฅผ headerview๋ก ๊ตฌํํ๋ ค๊ณ ํ์ด์. Detail view ๋ฐ์ ๊ฐ๋ ๋ฐ ๋ฑ์ฅ์ธ๋ฌผ์ด๋ผ๋ section header๊ฐ ์กด์ฌํ๋ฏ๋ก ๋ ๊ฐ์ header๋ฅผ ๊ฐ์ง๊ฒ ๋๋ ๋ ์ด์์์ด์์ด์. Table view์ ๊ฒฝ์ฐ, ๋ ๊ฐ์ header view๋ฅผ ๊ตฌํํ๋ ๊ฒ์ด ์์ฐ์ค๋ฝ์ง๋ง, collection view์ ๊ฒฝ์ฐ 2๊ฐ์ header view๋ฅผ ๊ฐ์ง๋ ๊ฒ์ด ์ด์ํ์ด์. ๊ทธ๋์ ๋ ์ข์ ๋ฐฉ์์ด ์์ง ์์๊น ๊ณ ๋ฏผํ๊ฒ๋์์ด์.
- collection view๋ scroll view๋ฅผ ์์ ๋ฐ๋ ํ์ ์ด์์. ๋ฐ๋ผ์ ์์ ๊ฐ์ด ๊ตฌํํ๋ฉด scroll view ์์ scroll view๋ฅผ ๋ฃ๊ฒ๋์. ์ ํ์ HIG ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํด๋ณธ ๊ฒฐ๊ณผ, ์ค์ฒฉ scroll view๋ฅผ ์ง์ํ๋ผ๊ณ ํ์ง๋ง, ์๋ก ๋ค๋ฅธ ๋ฐฉํฅ์ scroll view์ ์ค์ฒฉ์ ๋ฌธ์ ๊ฐ ๋์ง ์์์ ์๊ฒ๋์์ด์. ๊ทธ๋ฌ๋, scroll view๋ฅผ ํ์ฉํด์ ์๊ธฐ๋ ๊น๋ค๋ก์ด ๋ ์ด์์ ์ก๊ธฐ ๊ณผ์ ์ ํผํ๊ณ ์ถ์ด 4๋ฒ์งธ ๋ฐฉ๋ฒ์ ์๊ฐํ๊ฒ๋์ด์.
Avoid putting a scroll view inside another scroll view with the same orientation. Doing so creates an unpredictable interface thatโs difficult to control. Itโs alright to place a horizontal scroll view inside a vertical scroll view (or vice versa), however.
- ์ฒซ ๋ฒ์งธ section์๋ detail view cell ํ๋๋ง์ ๋ณด์ฌ์ฃผ๊ณ , ๋ ๋ฒ์งธ section์์๋ credit view๋ฅผ ๋ณด์ฌ์ฃผ๋ ๋ฐฉ์์ผ๋ก ๊ตฌํ์ ํ์ด์. ํด๋น ๋ฐฉ๋ฒ์ ํ์ฉํ๋, ์ ์ฒด ํ๋ฉด์ด scroll์ด ๋๋ฉด์ ์ํ๋ layout์ ๊ตฌํํ ์ ์์์ด์.
๐ Please Open
- feat. cell์์ ๋ฒํผ ๋ฃ๊ธฐ
๋ํ ์ผ ๋ทฐ |
---|
- Detail view์์ ๋๋ณด๊ธฐ ๋ฒํผ์ ์ถ๊ฐํ์ฌ ๋ฒํผ์ ๋๋ฅด๋ฉด label์ numberOfLines๊ฐ ๋ณ๊ฒฝ๋์ด, cell์ height๊ฐ ๋์ด๋๋ ๋์ ์ธ cell์ ๋ง๋๋ ค๊ณ ํ์ด์.
- Delegate ํจํด์ ํตํ์ฌ button ํญ์ด ๋๋ฉด, view controller๊ฐ label์ numberOfLines๋ฅผ ๋ณ๊ฒฝํ๊ณ , button์ ํ์ดํ์ ๋ณ๊ฒฝํ๋๋ก ๊ตฌํํ์ด์.
// ๐ delegate ํจํด ํ์ฉ!
protocol MovieDetailFirstSectionViewDelegate: AnyObject {
func movieDetailFirstSectionView(
_ movieDetailFirstSectionView: MovieDetailFirstSectionView,
didButtonTapped sender: UIButton
)
}
- ๋ํ NSCollectionLayoutSection์ ๊ตฌํํ๋ ์ฝ๋์์ itemsize ๋ฐ groupsize๋ฅผ
.fractional
์ด๋.absolute
๊ฐ ์๋.estimated
์ ํตํ์ฌ ๊ตฌํํ์ด์. ๋ํ, view์์ layout์ ๊ธฐ์กด์equalTo
๊ฐ ์๋greaterThanEqual
๋ฑ์ผ๋ก ๊ตฌํ์ ํด์ฃผ์์ด์.
// ๐ฟ in MovieDetailViewController
private func createDetailLayout() -> NSCollectionLayoutSection {
let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1),
// ๐ฆ .estimated ํ์ฉ
heightDimension: .estimated(600)
)
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1),
heightDimension: .estimated(600)
)
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
return section
}
๐ Please Open
- MVC ๊ตฌ์กฐ๋ก ๋ก์ง์ ์ง๋ค๋ณด๋, view controller๊ฐ ๋ง์ด ๋ฌด๊ฑฐ์์ก์ด์. View controller๋ collection view๋ฅผ ๊ตฌํํ๋ ๋ค์ํ ๋ก์ง๊ณผ ๋ค๋ฅธ delegate์ ์ฑํํ ๋ค์ํ ๋ฉ์๋๊ฐ ์กด์ฌํ์ด์. ๋ํ, Networking์ ํ๋ฉฐ ํ์ํ data๋ฅผ ๋ฐ์์ค๋ ๋ก์ง ๋ํ view controller๊ฐ ๊ด์ฅํ๊ณ ์์์ด์.
- ์ ๋ ๋๋ฌด ์ปค์ง view controller์ ์ญํ ์ ์ค์ด๊ธฐ ์ํ์ฌ controller๋ผ๋ ๋ชจ๋ธ ํ์ ์ ์์ฑํ์ด์. ํด๋น ํ์ ์ MVC ๊ตฌ์กฐ์์ Model์ ์ญํ ์ด๋ฉฐ ๋ฐ์ดํฐ์ ๊ด๋ จ๋ ๋ด์ฉ ๋ฐ ๋ก์ง์ ๊ฐ์ง๊ณ ์์ง๋ง, UI์๋ ์ง์ ์ ์ผ๋ก ์ฐ๊ฒฐ๋์ง ์์์. ์ฆ, Model ํ์ ์ view controller๋ฅผ ๋ชจ๋ฅด์ง๋ง, view controller๋ model์ ๋ด๋ถ ํ๋กํผํฐ๋ก ๊ฐ์ง๊ณ ์์ด์.
- Model์ API ํต์ ์ ํตํ์ฌ view controller๊ฐ collection view์ ๋์ธ ๋ ํ์ฉํ๋ ๋ฐ์ดํฐ ๋ชจ๋ธ ํ์ ์ ์์ฑํด์. ๊ทธ๋ฆฌ๊ณ model ํ์ ์ ์์ฑํ๋ฉด observer ํจํด์ ํตํ์ฌ view controller์๊ฒ model์ด ์์ฑ๋์์์ ์๋ ค์ฃผ๊ณ , view controller๋ ํด๋น model์ ํตํ์ฌ collection view๋ฅผ ๋์ฐ๊ฒ ๋ผ์.
๐ Controller
- MovieDetailController
final class MovieDetailModel {
private let movie: Movie
// ๐ ๋คํธ์ํฌ ๊ฐ์ฒด
private let movieNetworkAPIManager = NetworkAPIManager()
private let movieNetworkDispatcher = NetworkDispatcher()
...
private func fetchMovieDetails() {
// ๐ฅ ๋ฐ์ดํฐ ๋ชจ๋ธ ์์ฑ
guard let movieID = movie.ID else { return }
let movieDetailEndPoint = MovieDetailsAPIEndPoint(movieCode: movieID)
let movieCertificationEndPoint = MovieCertificationAPIEndPoint(movieCode: movieID)
Task {
do {
....
}
} catch {
....
}
NotificationCenter.default.post(
name: NSNotification.Name("MovieDetailModelDidFetchCreditData"),
object: nil
)
}
}
๐ ViewController
- MovieDetailViewController
// ๐ฟ in configureNotificationCenter()
NotificationCenter.default.addObserver(
self,
selector: #selector(didFetchMovieCreditsData(_:)),
name: NSNotification.Name("MovieDetailModelDidFetchCreditData"),
object: nil
)
// ๐ฟ in MovieDetailViewController
@objc private func didFetchMovieCreditsData(_ notification: Notification) {
DispatchQueue.main.async {
self.movieDetailCollectionView.reloadSections([Section.credit.rawValue])
}
}
๐ฌ ์ด๋ฅผ ํตํด์, view controller๋ view์ ๊ด๋ จ ์๋ ์ฝ๋๋ฅผ ๋์ด๋ผ ์ ์์๊ณ , view controller์ ์ญํ ์ด ๋ง์์ ธ์ ๋จ์ด์ง๋ ์ฝ๋์ ๊ฐ๋ ์ฑ ๊ฐ์ ํ ์ ์์์ด์.
๐ Please Open
- ํด๋น ์ฑ์ NotificationCenter๋ฅผ ํ์ฉํ์ฌ view๋ฅผ ์ ๋ฐ์ดํธํ๋ ๋ก์ง์ ํ์ฉํด์.
- ๊ทธ๋ฆฌ๊ณ navigation controller๋ฅผ ํ์ฉํ์ฌ push๊ฐ ๋๊ณ pop์ด๋๋ฉด pop๋ view controller๋ ์๋์ผ๋ก deinit์ด ๋๋ฉด์ NotificationCenter๊ฐ ์๋์ผ๋ก remove๊ฐ ๋ผ์.
์๋์ ์ ํ ๊ณต์๋ฌธ์๋ฅผ ์ฝ์ด๋ณด๋ฉด ๊ฐ๋ฐ์๊ฐ ์ง์ ์ ์ผ๋ก NotificationCenter๋ฅผ removeํ์ง ์์๋ ๋จ์ ์ ์ ์์ด์.
Unregister an observer to stop receiving notifications. To unregister an observer, use removeObserver(:) or removeObserver(:name:object:) with the most specific detail possible. For example, if you used a name and object to register the observer, use the name and object to remove it. If your app targets iOS 9.0 and later or macOS 10.11 and later, you do not need to unregister an observer that you created with this function. If you forget or are unable to remove an observer, the system cleans up the next time it would have posted to it.
- ๊ทธ๋ฌ๋, ํ๋ก์ ํธ ์งํ ์ค Notification์ด ์ค๋ณต์ผ๋ก ๋ฐ์์ง๋ ๊ฒฝ์ฐ๋ฅผ ํ์ธํ์ด์.
- Home viewcontroller์์ detail viewcontroller๋ก ๋์ด๊ฐ ๋, NotificationCenter๋ฅผ addObserver๋ฅผ ํ๋ ๋ฐ, detail view controller๊ฐ pop๋ ๋์ Notification center๊ฐ remove๊ฐ ๋์ง ์์ผ๋ฏ๋ก, ๊ณ์ํด์ Notification์ด ์ค๋ณต์ผ๋ก ๋ฐ์์ง๋ ๊ฒ์ด์์ด์.
๐๏ธ ์์ ๊ฐ์ ์ํฉ์ด ์ผ์ด๋๋ ์ด์ ๋ detail view controller๊ฐ pop๋ ๋, view controller ์ ํด๋ก์ ธ๋ delegate ๋ณ์์ ์ํด์ ์ํ์ฐธ์กฐ๊ฐ ์ผ์ด๋ ๋ฉ๋ชจ๋ฆฌ์์ ํ ๋น ํด์ (deinit)์ด ๋์ง ์๊ธฐ ๋๋ฌธ์ด์์ด์.
- ๋ฐ๋ผ์ ์๋์ ๊ฐ์ด ์ฝํ ์ฐธ์กฐ(weak)๋ฅผ ํ์ฉํ์ฌ view controller๊ฐ pop๋ ๋, ๋ฉ๋ชจ๋ฆฌ์์ ํ ๋น ํด์ ๊ฐ ๋ ์ ์๊ฒ ๋ณ๊ฒฝํด์ฃผ์์ด์.
private func createlayout() -> UICollectionViewCompositionalLayout {
let layout = UICollectionViewCompositionalLayout { [weak self] sectionIndex, layoutEnvironment in
let sectionType = Section.allCases[sectionIndex]
switch sectionType {
case .detail:
return self?.createDetailLayout()
case .credit:
return self?.createCreditLayout()
}
}
return layout
}
๐ฌ ์ด๋ฅผ ํตํด์, pop๋ ๋, ์ ์์ ์ผ๋ก view controller๊ฐ ๋ฉ๋ชจ๋ฆฌ์์ ํ ๋น ํด์ ๊ฐ ๋์ด Notification์ด ์ค๋ณต์ผ๋ก ๋ฐ์์ง๋ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์์ด์.