iOS

[iOS]2025.05.23 RxDataSources

ioskkt 2025. 5. 23. 13:27

CollectionView 에서 RxDataSources를 쓰려면 우선

 

CellModel : Cell에 들어갈 데이터 구조

SectionModel : RxDataSources가 요구하는 구조, 섹션의 데이터 구조

ViewModel : 비즈니스 로직

CollectionViewCell : Cell UI

ViewController : CollectionVeiw UI

 

가 필요하다

 

CellModel에서는 Cell에 들어가는 데이터 구조를 먼저 정의해준다.

import Foundation

struct Beach {
    let name: String
    let imageName: String
    let temperature: String
    let weatherStatus: String
}

 

SectionModel에서는 RxDataSources가 요구하는 구조를 만들어준다. 섹션의 데이터 구조임.

import RxDataSources

// 섹션의 데이터 구조
struct BeachSection {
    var items: [Beach]
}

extension BeachSection: SectionModelType {
    // 섹션 안에 있는 아이템의 타입을 알려줌.
    typealias Item = Beach
    // 새로운 섹션이 생길때 생성자 호출.
    init(original: BeachSection, items: [Beach]) {
        self = original
        self.items = items
    }
}

섹션에는 여러개의 셀이 들어가므로, 셀을 배열 구조로 정의해준다.

cf) var header: String 추가 가능

 

RxDataSources에서 섹션 모델을 사용하려면, 반드시 SectionModelType 프로토콜을 채택해야함.

public protocol SectionModelType {
    associatedtype Item

    var items: [Item] { get }

    init(original: Self, items: [Item])
}

 

뷰 모델을 정의해준다.

섹션 모델(BeachSection)을 가져와서 [BeachSection]타입의 Observable로 바꿔줌.

import Foundation
import RxSwift

final class SurferCategoryViewModel {

    func fetchBeachSections() -> Observable<[BeachSection]> {
        let beaches = [
            Beach(name: "경포해변", imageName: "beach1", temperature: "21°C", weatherStatus: "맑음"),
            Beach(name: "속초해수욕장", imageName: "beach2", temperature: "19°C", weatherStatus: "흐림")
        ]
        let section = BeachSection(items: beaches)
        return Observable.just([section])
    }
}

이제 생성된 Observable을 구독하기 위해 ViewController를 만들어준다.

 

CollectionView에서 사용될 데이터 소스를 정의해줌.

//ViewController

// BeachSection 기반 컬렉션 뷰를 구성하기 위한 제네릭 타입의 데이터 소스.
private lazy var dataSource = RxCollectionViewSectionedReloadDataSource<BeachSection>(
             //SectionModel, collectionView, indexPath, item 순
        configureCell: { _, collectionView, indexPath, item in
            guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: SurferCell.self), for: indexPath) as? SurferCell else {
                return UICollectionViewCell()
            }
            cell.configure(with: item)
            return cell
        })
        
private func bindViewModel() {
        viewModel.fetchBeachSections()
            .bind(to: collection.rx.items(dataSource: dataSource))
            .disposed(by: disposeBag)
    }