RxDataSources 사용법
Posted on 2021-09-23 by GKSRUDTN99
Swift&Xcode
RxSwift
1. DataSource에 사용할 구조체 / 열거형들을 정의한다.
DataSource는 model(섹션 이름)과 items로 이루어져있다.
model과 items에 사용할 객체를 정의한다.
enum MypageSectionType {
case rental
case product
case payment
case option
}
enum MypageMenuType {
case rentalHistory
case settlement
case purchaseHistory
case myProduct
case suggestion
case point
case customerService
case setting
var title : String {
switch self {
case .myProduct: return "나의 물건함"
case .point: return "꾿포인트"
case .purchaseHistory: return "나의 예약"
case .rentalHistory: return "이웃의 예약"
case .settlement: return "꾸다 수익"
case .suggestion: return "요청한 물건"
case .customerService: return "고객센터"
case .setting: return "설정"
}
}
}
2. Reactor 안에 Section의 형태를 정의한다.
typealias를 사용해 정의한다.
typealias Section = SectionModel<MypageSectionType, MypageMenuType>
3. VC에 DataSource의 형태를 정의한다.
typealias DataSource = RxTableViewSectionedReloadDataSource<MypageViewReactor.Section>
4. VC에 Cell의 형태를 정의하는 클로저를 정의한다.
StoryBoard에서 reuseableCell을 정의해 두어야 한다!
Cell 클래스를 따로 지정하고 싶다면, dequeue 한 뒤에 as?로 해당 Cell 클래스로 변환해주고,
해당 Cell 클래스 내에 정의된 setCell를 cell.setCell(item)과 같은 형태로 호출하여 설정하면 된다.
아래tableview
자리에는 RxDatasource를 사용할 IBOutlet 객체가 들어가야한다.
private var configureCell: DataSource.ConfigureCell { return {
dataSource, tableView, indexPath, item -> UITableViewCell in
guard let cell = tableView.dequeueReusableCell(withIdentifier: "menuCell") else { return UITableViewCell() }
(cell.viewWithTag(1) as? UILabel)?.text = item.title
return cell
}}
5. VC에 DataSource 객체를 생성한다.
private lazy var itemsDataSource = DataSource {
configureCell: self.configureCell
}
6. 위의 두 과정을 바탕으로 아래의 Custom이 가능하다.
다른 Custom은 tableView나 CollectionView의 Delegate를 활용해야 한다.
dataSource.titleForHeaderInSection = ( dataSource, index in
return dataSource.sectionModels[index].header
)
dataSource.titleForFooterInSection = { dataSource, index in
return dataSource.sectionModels[index].footer
}
dataSource.canEditRowAtIndexPath = { dataSource, indexPath in
return true
}
dataSource.canMoveRowAtIndexPath = { dataSource, indexPath in
return true
}
7. section은 tableView/CollectionView의 Datasource에 바인딩한다.
State에 sections를 정의하고 VC에서 sections를 감지해 바인딩하기
class MypageViewController {
reactor.state.map { $0.sections }
.observeOn(MainScheduler.instance)
.distinctUntilChanged()
.bind(to: tableView.rx.items(dataSource: itemsDataSource))
.disposed(by: disposeBag)
}
class MypageViewReactor {
struct State {
let sections = [
Section(model: .rental, items: [.rentalHistory, .purchaseHistory]),
Section(model: .product, items: [.myProduct, .suggestion]),
Section(model: .payment, items: [.settlement, .point]),
Section(model: .option, items: [.customerService, .setting])
]
}
}
State에 products를 정의하고, products를 감지해 Section을 만들기
class VC {
reactor.state.map { $0.products }
.observeOn(MainScheduler.instance)
.distinctUntilChanged()
.compactMap { $0.data?.data }
.map { [Reactor.Section(model: "", items: $0)] }
.bind(to: self.collectionView.rx.items(dataSource: itemsDataSource))
.disposed(by: disposeBag)
}
class Reactor {
struct State {
var product = RevisionedData<Product>(data:nil)
}
}
8. 해당 item의 Action 정의하기
Action Binding
IndexPath로 binding하기
collectionView.rx.itemSelected
.map { indexPath in Reactor.Action.moveProductDetail(indexPath.item) }
.bind(to: reactor.action )
.disposed(by: disposeBag)
객체로 바인딩하기
tableView.rx.modelSelected(MypageMenuType.self)
.map { type in Reactor.Action.actionMenu(type) }
.bind(to: reactor.action)
.disposed(by: disposeBag)