swift

RxDataSources

motosw3600 2022. 5. 7. 17:02

RxDataSources

  • TableView, CollectionView를 Section을 사용해서 정의가능한 프레임워크
  • Rx를 사용한 반응형 데이터 적용
  • cellForRowAt을 사용하지 않고 cell데이터 지정
  • Link

Section정의

RxDataSource에 사용될 DataType은 SectionModelType을 준수

items는 cell데이터 타입 등록

struct SectionOfMain {
    var items: [Item]
}

extension SectionOfMain: SectionModelType {
    typealias Item = MainCellData
    
    init(original: Self, items: [Item]) {
        self = original
        self.items = items
    }
}

 

CellData정의

Section안에 정의한 item enumType으로 설정

(cellType은 TableView cell register부분에서 한번에 등록하기 위한 변수)

enum MainCellData {
    case main(title: String, isFocus: Bool)
    case sub(title: String)
    
    var cellType: MainCellDataProtocol.Type {
        switch self {
        case .main: return MainCell.self
        case .sub: return SubCell.self
        }
    }
}

protocol MainCellDataProtocol: AnyObject {
    func apply(item: MainCellData) // data 적용
    static func cellHeight(item: MainCellData) -> CGFloat // 동적 height설정
}

Cell정의

위에서 정의한 MainCellDataProtocol을 준수하는 Cell정의

class MainCell: UITableViewCell, MainCellDataProtocol {
    let titleLabel: UILabel = {
        let label = UILabel()
        label.text = "main"
        label.textColor = .purple
        label.font = .systemFont(ofSize: 20)
        return label
    }()
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        contentView.addSubview(titleLabel)
        
        titleLabel.snp.makeConstraints { make in
            make.center.equalToSuperview()
        }
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
    
    func apply(item: MainCellData) {
        guard case let .main(title, isFocus) = item else { return }
        titleLabel.text = title
        
        titleLabel.font = isFocus ? .boldSystemFont(ofSize: 20) : .systemFont(ofSize: 20)
    }
    
    static func cellHeight(item: MainCellData) -> CGFloat {
        return 70
    }
}

 

TabelView RxDataSource적용

// dataSource선언
private var dataSource: RxTableViewSectionedReloadDataSource<SectionOfMain>?

private func setupDataSource() {
	// dataSource정의 (기존 tableView(_: cellForRowAt.. 부분)
    let dataSource = RxTableViewSectionedReloadDataSource<SectionOfMain> {
        _, tableView, indexPath, item in
        let cellId = String(describing: item.cellType)
        tableView.register(item.cellType, forCellReuseIdentifier: cellId)
        tableView.register(item.cellType, forCellReuseIdentifier: cellId)
        let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
        (cell as? MainCellDataProtocol)?.apply(item: item)
        return cell
    }
    self.dataSource = dataSource
    
    // viewModel의 sections binding
    viewModel.sections
        .observe(on: MainScheduler.instance)
        .bind(to: tableView.rx.items(dataSource: dataSource))
        .disposed(by: disposeBag)
}

 

github linkg:  https://github.com/motosw3600/RxDataSourceEx

'swift' 카테고리의 다른 글

DropDown 오픈소스 라이브러리 만들기  (0) 2022.08.10
Custom ScrollPaging  (0) 2022.06.05
RxSwift UnitTest 해보기(RxTest, RxNimble)  (0) 2022.03.10
Tuist로 프로젝트 관리해보기  (0) 2022.03.05
The Composable Architecture(TCA)  (0) 2022.03.02