IAM iOS

[RxSwift] MVVM-C with Building Memo App (8) RxDataSources 적용 본문

RxSwift

[RxSwift] MVVM-C with Building Memo App (8) RxDataSources 적용

IAMiOS 2022. 5. 12. 01:30

 

해당 포스팅은 KxCoding RxSwift 강의를 참고한 포스팅입니다!

https://www.youtube.com/watch?v=m41N4czHGF4&list=PLziSvys01Oek7ANk4rzOYobnUU_FTu5ns&index=2

 

RxDataSources 적용


메모가 삭제될 때 row 애니메이션이 실행되도록 수정

 

Memo(Model)

RxDataSources를 import 하여 IdentifiableType 프로토콜 채택

  • dataSource에 저장되는 모든 데이터는 IdentifiableType 프로토콜 채택
  • IdentifiableType 프로토콜에는 Identity 속성이 Hashable을 채용한 형식으로 선언되어 있다.
public protocol IdentifiableType {
    associatedtype Identity: Hashable

    var identity : Identity { get }
}

 

Memo 구조체에는 이미 identity 속성이 String으로 선언되어있는데, String은 Hashable 프로토콜을 채용한 형식이므로 IdentifiableType 프로토콜이 요구하는 사항을 충족

struct Memo: Equatable, IdentifiableType {
    var content: String
    var insertDate: Date
    var identity: String

 

MemoListViewModel

TableView와 Binding되는 memoList 속성은 Observable이 Memo 배열을 방출하고 있다.

var memoList: Observable<[Memo]> {
    return storage.memoList()
}

 

이 부분을 RxDataSources가 요구하는 방식으로 바꿔야 한다.

  • SectionModel을 생성한 다음에 SectionData와 rowData를 저장하고, Observable이 SectionModel 배열을 방출하도록 수정
  • RxDataSources가 제공하는 기본 SectionModel인 AnimatableSectionModel을 사용
/// SectionData: Int, rowData: Memo
typealias MemoSectionModel = AnimatableSectionModel<Int, Memo>

 

TableView Binding에 사용할 dataSource 속성

let dataSource: RxTableViewSectionedAnimatedDataSource<MemoSectionModel> = {
    let ds = RxTableViewSectionedAnimatedDataSource<MemoSectionModel>(
        configureCell: { (dataSource, tableView, indexPath, memo
        ) -> UITableViewCell in
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.text = memo.content
        return cell
    })
    ds.canEditRowAtIndexPath = { _, _ in return true }
    return ds
}()

var memoList: Observable<[MemoSectionModel]> {
    return storage.memoList()
}

 

 

MemoStorageType

MemoStorageType의 memoList() 메서드도 반환 값 변경

@discardableResult
func memoList() -> Observable<[MemoSectionModel]>

 

MemoryStorage

  • MemoStorageType이 수정되었으니까 이 프로토콜을 채택한 MemoryStorage도 수정
  • Memo 배열을 방출하는 BehaviorSubject와 memoList()가 return 하는 Observable도 변경

 

list를 기반으로 새로운 SectionModel 생성

 private lazy var sectionModel = MemoSectionModel(model: 0, items: list)

 

BehaviorSubject에서 [Memo] → [MemoSectionModel]로 방출하도록 변경

private lazy var store = BehaviorSubject<[MemoSectionModel]>(value: [sectionModel])

 

  • createMemo, update, delete 메서드는 대상 배열을 바꾸고, sectionModel을 방출하도록 수정
    • list → sectionModel.items
    • store.onNext(list) → store.onNext([sectionModel])
  • memoList 메서드는 [MemoSectionModel]을 return 하도록 수정
@discardableResult
    func createMemo(content: String) -> Observable<Memo> {
        /// 새로운 memo를 생성하고 배열에 추가
        let memo = Memo(content: content)

        /// 대상 배열을 바꾸고, sectionModel을 방출하도록 수정
        sectionModel.items.insert(memo, at: 0)

        /// subject에서 새로운 next 이벤트를 방출
        store.onNext([sectionModel])

        /// 새로운 memo를 방출하는 Observable을 return
        return Observable.just(memo)
    }

    /// class 외부에서는 이 메서드를 통해 접근
    @discardableResult
    func memoList() -> Observable<[MemoSectionModel]> {
        return store
    }

 ...

 

 

MemoListViewController

앞서 MemoListViewModel에서 추가한 dataSource와 Binding

  • RxDataSources 적용 전
viewModel.memoList
    .bind(to: listTableView.rx.items(cellIdentifier: "cell")) { row, memo, cell in
        cell.textLabel?.text = memo.content
    }
    .disposed(by: rx.disposeBag)

 

  • viewModel의 dataSource와 Binding
viewModel.memoList
    .bind(to: listTableView.rx.items(dataSource: viewModel.dataSource))
    .disposed(by: rx.disposeBag)

 

RxDataSources 적용 후, 메모가 삭제될 때 row 애니메이션이 실행되는 결과 화면

 

 

코드 보러 가기

 

GitHub - camosss/RxSwift: RxSwift 공부한 내용 정리

RxSwift 공부한 내용 정리. Contribute to camosss/RxSwift development by creating an account on GitHub.

github.com