Before & After
| ๊ฐ์ ์ |
๊ฐ์ ํ |
ย |
 |
๋ฌธ์ ์ํฉ : Cell์ ๋ฐ์ดํฐ ํ์ ์ง์ฐ
cellForRowAt์์ ๋คํธ์ํฌ ๋ฐ ๋ ๋ฆ์์ CellModeld์ ๋น๋๊ธฐ์ ์ผ๋ก ๋ฐ์์ค๋ Publisher๋ฅผ ๋ง๋ ํ, cell์ bindํด์ฃผ๊ณ ์คํธ๋ฆผ์ ์์ํฉ๋๋ค.
- cell์ด ๋ํ๋๊ธฐ ์ง์ ์ ๋น๋๊ธฐ์์
์ด ์์๋๋ฏ๋ก, cell์ ๋ฐ์ดํฐ๋ฅผ ํ์ํ๊ธฐ๊น์ง ์ง์ฐ์ด ๋ฐ์ํฉ๋๋ค.
extension AppFolderDetailViewModel: UITableViewDataSource {
func tableView(
_ tableView: UITableView,
numberOfRowsInSection section: Int)
-> Int
{
if let savedApps,
savedApps.isEmpty {
showEmptyView.send(true)
} else {
showEmptyView.send(false)
}
return savedApps?.count ?? 0
}
func tableView(
_ tableView: UITableView,
cellForRowAt indexPath: IndexPath)
-> UITableViewCell
{
let cell = tableView.dequeueReusableCell(
withClass: SavedAppDetailTableViewCell.self,
for: indexPath)
guard let savedApp = savedApps?[safe: indexPath.row] else {
return cell
}
// TODO: - Error Handling
let cellModel = appFolderUsecase.readSavedAppDetail(of: savedApp)
.map { savedAppDetail in
return SavedAppDetailTableViewCellModel(savedAppDetail: savedAppDetail)
}
.assertNoFailure()
.eraseToAnyPublisher()
cell.bind(cellModel)
return cell
}
}
ํด๊ฒฐ ๋ฐฉ๋ฒ : UITableViewDataSourcePrefetching ์ฌ์ฉ
UITableViewDataSourcePrefetching๋ฅผ ์ฑํํ์ฌ tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) ๋ฉ์๋๋ด์์ [indexPath]์ ํด๋นํ๋ savedApp๋ค์ cellModel์ ๋ค์ด๋ก๋ํ์ฌ ๋ฐฐ์ด์ ์ ์ฅํฉ๋๋ค.
extension AppFolderDetailViewModel: UITableViewDataSourcePrefetching {
func tableView(
_ tableView: UITableView,
prefetchRowsAt indexPaths: [IndexPath])
{
guard let savedApps else {
return
}
Publishers.Sequence<[IndexPath], Never>(sequence: indexPaths)
.map({ indexPath in
return (indexPath.row, savedApps[indexPath.row])
})
.flatMap { (index, savedApp) -> AnyPublisher<(Int, SavedAppDetail), Error> in
return self.appFolderUsecase.readSavedAppDetail(of: savedApp, index: index)
}
.map{ savedAppDetail in
return (savedAppDetail.0, SavedAppDetailTableViewCellModel(savedAppDetail: savedAppDetail.1))
}
.assertNoFailure()
.sink { [unowned self] cellModel in
self.fetchedCellModels[cellModel.0] = cellModel.1
}.store(in: &cancellable)
}
}
tableView( _ tableView: UITableView, cellForRowAt indexPath: IndexPath)์์ ๋ง์ฝ prefetchํ cellModel์ด ์๋ค๋ฉด ํด๋น cellModel์ ์ฌ์ฉํด ๋ฐ์ธ๋ํ๊ณ , ์๋ค๋ฉด ์คํธ๋ฆผ์ ์์ํฉ๋๋ค.
extension AppFolderDetailViewModel: UITableViewDataSource {
func tableView(
_ tableView: UITableView,
numberOfRowsInSection section: Int)
-> Int
{
if let savedApps,
savedApps.isEmpty {
showEmptyView.send(true)
} else {
showEmptyView.send(false)
}
return savedApps?.count ?? 0
}
func tableView(
_ tableView: UITableView,
cellForRowAt indexPath: IndexPath)
-> UITableViewCell
{
let cell = tableView.dequeueReusableCell(
withClass: SavedAppDetailTableViewCell.self,
for: indexPath)
guard let savedApp = savedApps?[safe: indexPath.row] else {
return cell
}
if let cellModel = fetchedCellModels[indexPath.row] {
cell.bind(cellModel)
} else {
let cellModel = appFolderUsecase.readSavedAppDetail(of: savedApp)
.map { savedAppDetail in
return SavedAppDetailTableViewCellModel(savedAppDetail: savedAppDetail)
}
.assertNoFailure()
.eraseToAnyPublisher()
cell.bind(cellModel)
}
return cell
}
}
์ถ๊ฐ ๋ณด์์
prefetchRowsAt๋ฉ์๋๋ ์ฌ์ฉ์๊ฐ ์คํฌ๋กค์ ํด์ผ ํธ์ถ๋๊ธฐ ๋๋ฌธ์ ๋งจ ์ฒ์ ๋ณด์ฌ์ง๋ ์
์ ์ฌ์ ํ ์ง์ฐ์ด ๋ฐ์ํฉ๋๋ค.
Before & After
๋ฌธ์ ์ํฉ : Cell์ ๋ฐ์ดํฐ ํ์ ์ง์ฐ
cellForRowAt์์ ๋คํธ์ํฌ ๋ฐ ๋ ๋ฆ์์ CellModeld์ ๋น๋๊ธฐ์ ์ผ๋ก ๋ฐ์์ค๋ Publisher๋ฅผ ๋ง๋ ํ, cell์ bindํด์ฃผ๊ณ ์คํธ๋ฆผ์ ์์ํฉ๋๋ค.ํด๊ฒฐ ๋ฐฉ๋ฒ :
UITableViewDataSourcePrefetching์ฌ์ฉUITableViewDataSourcePrefetching๋ฅผ ์ฑํํ์ฌtableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath])๋ฉ์๋๋ด์์ [indexPath]์ ํด๋นํ๋ savedApp๋ค์ cellModel์ ๋ค์ด๋ก๋ํ์ฌ ๋ฐฐ์ด์ ์ ์ฅํฉ๋๋ค.tableView( _ tableView: UITableView, cellForRowAt indexPath: IndexPath)์์ ๋ง์ฝ prefetchํ cellModel์ด ์๋ค๋ฉด ํด๋น cellModel์ ์ฌ์ฉํด ๋ฐ์ธ๋ํ๊ณ , ์๋ค๋ฉด ์คํธ๋ฆผ์ ์์ํฉ๋๋ค.์ถ๊ฐ ๋ณด์์
prefetchRowsAt๋ฉ์๋๋ ์ฌ์ฉ์๊ฐ ์คํฌ๋กค์ ํด์ผ ํธ์ถ๋๊ธฐ ๋๋ฌธ์ ๋งจ ์ฒ์ ๋ณด์ฌ์ง๋ ์ ์ ์ฌ์ ํ ์ง์ฐ์ด ๋ฐ์ํฉ๋๋ค.