WooKoo Blog

물과 같이

개발/개발

[iOS] - RxDataSource로 테이블뷰 헤더 푸터 그리기 (MVVM)

WooKoo 2022. 4. 4. 23:17

Rx를 이용해서 테이블 뷰의 헤더뷰나 푸터뷰를 그려야할 경우가 있을 것이다.

 

기존에 tableView.rx.items를 이용해서 테이블 뷰를 그렸겠지만 헤더뷰와 푸터뷰, 섹션 등을 사용하려면

RxDataSource를 이용해야한다.

 

그거에대한 방법을 자세하게는 아니고 정리해보려고한다.

 

 

RxDataSources를 라이브러리를 추가한다.

 

https://github.com/RxSwiftCommunity/RxDataSources

 

GitHub - RxSwiftCommunity/RxDataSources: UITableView and UICollectionView Data Sources for RxSwift (sections, animated updates,

UITableView and UICollectionView Data Sources for RxSwift (sections, animated updates, editing ...) - GitHub - RxSwiftCommunity/RxDataSources: UITableView and UICollectionView Data Sources for RxSw...

github.com

그 다음에!

RxDatasource는 Section이라는 AnimatableSectionModelType을 채택한 구조체를 사용한다.

 

나는 푸터뷰를 만들고 싶어서 푸터로했다. 헤더면 헤더로 바꾸면 되겠다!

struct MySection{
    var footerTitle: String
    var items: [Item]
}
extension MySection: AnimatableSectionModelType{
   
    
    typealias Item = ModelElementType
    
    var identity: String{
        return footerTitle
    }
    
    init(original: MySection, items: [ModelElementType]) {
        self = original
        self.items = items
    }
    
}

이렇게 테이블 뷰에 여러 섹션이 있을 수도 있어서 타입을 강제화하는 것 같다.

 

그 후 TableView의 델리게이트를 지정

(저는 viewDidLoad에 했어요)

    tableView.rx.setDelegate(self)
               .disposed(by: disposeBag)

그러고나서 전역 변수를 선언해줬어요 BehaviorRelay타입으로요

왜냐면 저는 뷰모델에서 api요청한 Relay랑 바인딩해주고싶었거든요

 

var sectionSubject = BehaviorRelay(value: [MySection]())

 

그 후에 

 

var dataSource = RxTableViewSectionedReloadDataSource<MySection> { dataSource, tableView, indexPath, item in
            let cell = tableView.dequeueReusableCell(withIdentifier: "cell.identifier", for: indexPath) as! customCell
            
            cell.drawView()
            
            return cell
            
            
            
        }

바인딩 함수 안에 작성해주자!

 

푸터뷰에 타이틀할거면 

 

 dataSource.titleForFooterInSection = { dataSource, index in
            return "제목 입력하기~"
            
        }

 

이렇게하면 되구

 

뷰모델에 Relay에서 데이터 가져오고 싶으면 이런식으로 쓰자

   viewModel.relayModel
            .withUnretained(self)
            .subscribe(onNext:{ a, b in
                let sections = [
                    MySection(footerTitle: "푸터 제목 상관 없음", items: b)
                ]
                self.sectionSubject.accept(sections)
            }).disposed(by: disposeBag)
            
           
        sectionSubject
              .bind(to: tableView.rx.items(dataSource: dataSource))
              .disposed(by: disposeBag)

뷰모델에 데이터에 구독을 추가하고 우리의 sectionSubject에 accept!!

하고 테이블 뷰와 sectionSubject 바인딩해주면

 

끝!!