[RxSwift] RxDataSources

Junyoung Park·2022년 8월 31일
0

RxSwift

목록 보기
6/25
post-thumbnail

RxSwift Beginners Episode 6 - RxDataSources

RxDataSources

구현 목표

  • UITableView의 데이터 소스 델리게이트 함수의 RxSwift화
  • 서치 바의 텍스트에 따라 반응형 테이블 뷰를 그렸던 것과 마찬가지로 해당 섹션에 대한 아이템 필터링

구현 태스크

  1. RxDataSources 임포트
  2. RxDataSources

핵심 코드

import Foundation
import RxDataSources

struct SectionModel {
    let header: String
    var items: [FoodModel]
}

extension SectionModel: SectionModelType {
    init(original: SectionModel, items: [FoodModel]) {
        self = original
        self.items = items
    }
}
  • 테이블 뷰의 섹션에 바인딩되는 데이터 모델
  • SectionModelType에 따라 현재 섹션 모델 정보 및 변경된 아이템으로 세팅 → 섹션 내 아이템의 변동을 감지 가능
let tableViewItemSection = [SectionModel(header: "Main Courses", items: [FoodModel(name: "Hamburger", imageName: "hamburger"), FoodModel(name: "Pizza", imageName: "pizza"), FoodModel(name: "Bulgogi", imageName: "bulgogi")]), SectionModel(header: "Desserts", items: [FoodModel(name: "Coke", imageName: "coke")])]
    lazy var tableViewItemSectionsRx = BehaviorRelay.init(value: tableViewItemSection)
  • 기존 데이터 모델을 섹션과 함께 세팅한 tableViewItemSection
  • 해당 섹션 데이터를 BehaviorRelay로 이니셜라이즈 → 변화 감지 및 곧바로 작업을 수행 가능한 Observable + Observer
let dataSource = RxTableViewSectionedReloadDataSource<SectionModel>(configureCell: {
        ds, tv, indexPath, item in
        let cell: CustomTableViewCell
        if let dequeuedCell = tv.dequeueReusableCell(withIdentifier: "customTableViewCell", for: indexPath) as? CustomTableViewCell {
            cell = dequeuedCell
        } else {
            cell = CustomTableViewCell()
        }
        cell.cellLabel.text = item.name
        cell.cellImage.image = UIImage(named: item.imageName)
        return cell
    }, titleForHeaderInSection: {
        ds, index in
        return ds.sectionModels[index].header
    })
  • 위 섹션 모델을 통해 구성한 RxDataSources
  • 주어진 데이터에 따라 커스텀 셀을 바인딩, 해당 섹션의 헤더를 섹션 모델의 값으로 바인딩한 결과를 리턴
private func setSearchingTableViewWithSection() {
        searchBar.rx.text.orEmpty
            .throttle(.milliseconds(300), scheduler: MainScheduler.instance)
            .distinctUntilChanged()
            .map { query in
                self.tableViewItemSectionsRx.value.map { sectionModel in
                    SectionModel(header: sectionModel.header, items: sectionModel.items.filter({ foodModel in
                        if query.isEmpty || foodModel.name.lowercased().contains(query.lowercased()) {
                            return true
                        } else {
                            return false
                        }
                    }))
                }
            }
            .bind(to: tableView
                .rx
                .items(dataSource: dataSource))
            .disposed(by: disposeBag)
    }
  • 기존 서치 바 텍스트에 따라 테이블 뷰 아이템을 필터링한 것과 마찬가지로 텍스트 변화에 따라 필터링된 결과를 섹션 내에서도 하고 있는 코드
  • map 고차 함수 클로저 내부에서 해당 섹션 내 아이템이 현재 검색된 서치 바 텍스트와 일치되는지를 필터링, 불리언 값으로 리턴
  • 매핑된 결과값을 통해 매칭된 아이템이 존재한다면 해당 데이터소스를 그대로 아이템으로 바인딩하는 .items(dataSource:) 메소드

구현 화면

섹션 정보까지 매우 간단하게 RxSwift화할 수 있다는 것을 배웠다!

profile
JUST DO IT

0개의 댓글