Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- 리펙터링
- rxswift
- 리펙토링
- SWIFT
- 스위프트
- uiscrollview
- 리팩토링
- tableView
- HIG
- ios
- collectionview
- Clean Code
- swift documentation
- 애니메이션
- 클린 코드
- UITextView
- Observable
- uitableview
- Protocol
- Xcode
- swiftUI
- Human interface guide
- Refactoring
- MVVM
- clean architecture
- combine
- RxCocoa
- ribs
- UICollectionView
- map
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] 1. ReactorKit 샘플 앱 - RxDataSources 사용 방법 본문
1. ReactorKit 샘플 앱 - RxDataSources 사용 방법
2. ReactorKit 샘플 앱 - RxDataSources을 이용한 Section, Item 모델 구현 패턴 (with 동적 사이즈 셀)
기초
ReactorKit + RxDataSources 사용 방향
- RxDataSources를 사용하면 extension으로 따로 tableView의 cellForRowAt 메소드를 따로 빼지 않아도 간결한 코드 작성이 가능
- Cell에 사용될 상태 관리 전용 Reactor 생성
- Cell에 UI를 업데이트 할 때 이 Reactor 인스턴스를 받아서 사용
- 정의한 Cell 클래스에 bind(reactor:) 함수를 정의하여, 이곳에 데이터들을 넘기도록 설계
Cell 전용 Reactor를 두는 이유
- Cell 전용 Reactor를 두고 사용할 때 아래와 같이 cell.reactor로 reactor를 바로 대입하여 사용 가능
var dataSource = RxTableViewSectionedReloadDataSource<MainSection> { dataSource, tableView, indexPath, reactor in let cell = tableView.dequeueReusableCell(for: indexPath) as MainTableViewCell cell.reactor = reactor return cell }
- Cell 전용 Reactor가 없다면 별도의 bind(model:) 메소드를 번거롭게 Cell쪽에 만들어야 하는 단점 존재
var dataSource = RxTableViewSectionedReloadDataSource<MainSection> { dataSource, tableView, indexPath, reactor in let cell = tableView.dequeueReusableCell(for: indexPath) as MainTableViewCell let item = dataSource[indexPath] cell.bind(model: item) return cell }
하나의 TableView에 다수의 Cell들을 처리 과정
1. Cell에서 사용할 Model 정의
2. ViewCell과 ViewCellReactor 정의
- ViewCell은 데이터가 표출될 UI 요소
- ViewCellReactor는 Model을 state값으로 가지고 있는 컴포넌트
3. ViewSection 정의
- RxDataSources에서 사용될 모델이고, Section별, Item별로 데이터 구조화
1. Cell에서 사용할 Model 정의
- 정의할 Cell들이 사용할 때 공통으로 갖을 protocol 정의
- Then - SwiftUI와 유사하게 클로저를 통해 편리하게 접근 가능
- Codable - decode & encode
- Equatable - RxDataSources의 모델에 들어가면 필수로 준수해야하는 프로토콜
// ModelType.swift import Then protocol ModelType: Then, Codable, Equatable { }
- Cell에 들어갈 Model 정의 (2가지 셀을 사용할것이므로, 2개의 모델 정의 Main, Sub)
- ModelType을 준수하고, `==` 연산자 구현
// Main.swift import RxDataSources struct Main: ModelType { var message: String var isDone = false } extension Main: Equatable { static func == (lhs: Main, rhs: Main) -> Bool { lhs.message == rhs.message } }
- Sub 모델도 동일하게 구현
// Sub.swift import UIKit struct Sub: ModelType { var message: String var isDone = false } extension Sub: Equatable { static func == (lhs: Sub, rhs: Sub) -> Bool { lhs.message == rhs.message } }
- ModelType을 준수하고, `==` 연산자 구현
2. ViewCell과 ViewCellReactor 정의
- ViewCellReactor 정의
- state타입에 사용할 모델 선언 let initialState: {사용할 모델 타입}
// MainTableViewCellReactor.swift import ReactorKit class MainTableViewCellReactor: Reactor { typealias Action = NoAction let initialState: Main init(main: Main) { self.initialState = main } }
- state타입에 사용할 모델 선언 let initialState: {사용할 모델 타입}
- ViewCell 정의
- UITableViewCel, View, Reusable을 준수
- bind(reactor:) 메소드 구현
// MainTableViewCell.swift import UIKit import Reusable import SnapKit import ReactorKit class MainTableViewCell: UITableViewCell, View, Reusable { ... // MARK: Binding func bind(reactor: MainTableViewCellReactor) { titleLabel.text = "(메인) " + reactor.currentState.message } }
- SubTableViewCellReactor, SubTableViewCell도 동일하게 구현
3. ViewSection 정의
- SomeViewSection은 RxDataSources의 모델에 사용
- Section과 Item에서 사용할때는 enum으로 선언하고, enum으로 구분 후 associative type으로 모델을 선언
- SomeViewSection - Section에 사용될 타입
- SomeViewSectionItem - Item에 사용될 타입
// SomeViewSection.swift import RxDataSources enum SomeViewSection { case first([SomeViewSectionItem]) } enum SomeViewSectionItem { case main(MainTableViewCellReactor) case sub(SubTableViewCellReactor) }
- RxDataSources의 모델로 사용을 위해서, SectionModelType이라는 프로토콜을 준수
extension SomeViewSection: SectionModelType { var items: [SomeViewSectionItem] { switch self { case .first(let items): return items } } init(original: SomeViewSection, items: [SomeViewSectionItem]) { switch original { case .first: self = .first(items) } } }
- 전체 SomeViewSection 코드
enum SomeViewSection { case first([SomeViewSectionItem]) } enum SomeViewSectionItem { case main(MainTableViewCellReactor) case sub(SubTableViewCellReactor) } extension SomeViewSection: SectionModelType { var items: [SomeViewSectionItem] { switch self { case .first(let items): return items } } init(original: SomeViewSection, items: [SomeViewSectionItem]) { switch original { case .first: self = .first(items) } } }
RxDataSources 사용
- 핵심은 ViewController에서 RxTableViewSectinoedReloadDataSource<SomeVIewSection>으로 사용
// MainViewController.swift import ReactorKit import RxDataSources import Reusable final class MainViewController: UIViewController, View { ... var dataSource = RxTableViewSectionedReloadDataSource<SomeViewSection> { dataSource, tableView, indexPath, sectionItem in switch sectionItem { case .main(let reactor): let cell = tableView.dequeueReusableCell(for: indexPath) as MainTableViewCell cell.reactor = reactor return cell case .sub(let reactor): let cell = tableView.dequeueReusableCell(for: indexPath) as SubTableViewCell cell.reactor = reactor return cell } } ... }
* 전체 소스 코드: https://github.com/JK0369/RxReactorKit-RxDataSources
'iOS framework' 카테고리의 다른 글
[iOS - swift] 2. ReactorKit 샘플 앱 - RxDataSources을 이용한 Section, Item 모델 구현 패턴 (with 동적 사이즈 셀) (2) | 2021.12.16 |
---|---|
[iOS - swift] Moya, RxMoya, Networking 레이어 (6) | 2021.12.13 |
[iOS - swift] Reusable 프레임워크 사용 방법 (0) | 2021.12.10 |
[iOS - swift] 1. Kingfisher 프레임워크 (이미지 캐싱, 이미지 로드) - 사용 방법 (0) | 2021.12.09 |
[iOS - framework] ImagePickerController의 framework (0) | 2020.05.23 |
Comments