TodoAppでRxSwift入門[part4]
概要
最近RxSwiftを勉強し始めて現在理解していることを備忘録として残せたらいいなと思い記事にします。
そもそもRxSwiftのRxとは
Rx(Reactive X)とは、「オブザーバパターン」「イテレータパターン」「関数型プログラミング」の概念を実装している拡張ライブラリです。
Rxを導入するメリットは、「値の変化を検知できる」「非同期の処理を簡潔に書ける」ということに尽きると思います。 値の変化というのは変数値の変化やUIの変化も含まれます。 例えばボタンをタッチする、という動作もボタンのステータスが変わったと捉えることができRxを使って記述することができます。
とのことです。
詳しくは以下のサイトを参照してください。
入門!RxSwift
RxSwiftについてようやく理解できてきたのでまとめることにした(1)
今回はPart3になります。
前回の記事はこちら
TodoAPPでRxSwift入門[part3]
今回でうまく修まれば最後になります。
TodoListViewModel
TodoListViewModel.swift
// Cellに渡す時に扱いやすいようにしています。
typealias TodoItemsSection = SectionModel<Int, TodoCellViewPresentable>
protocol TodoListPresentable {
typealias Input = ()
typealias Output = (
todos: Driver<[TodoItemsSection]>, ()
)
var input: TodoListPresentable.Input { get }
var output: TodoListPresentable.Output { get }
}
class TodoListViewModel: TodoListPresentable {
var input: TodoListPresentable.Input
var output: TodoListPresentable.Output
private let storeManager: StoreManager
init(input: TodoListPresentable.Input, storeManager: StoreManager) {
self.input = input
self.storeManager = storeManager
self.output = TodoListViewModel.output(storeManager: self.storeManager)
}
}
private extension TodoListViewModel {
static func output(storeManager: StoreManager) -> TodoListPresentable.Output {
let todos = storeManager.fetchTodosFromFirestore()
.map { $0.compactMap { TodoCellViewModel(usingModel: $0) } }
.map { [TodoItemsSection(model: 0, items: $0)] }
.asDriver(onErrorJustReturn: [])
return (
todos: todos, ()
)
}
}
// Cellに渡す時に扱いやすいようにしています。
typealias TodoItemsSection = SectionModel<Int, TodoCellViewPresentable>
protocol TodoListPresentable {
typealias Input = ()
typealias Output = (
todos: Driver<[TodoItemsSection]>, ()
)
var input: TodoListPresentable.Input { get }
var output: TodoListPresentable.Output { get }
}
class TodoListViewModel: TodoListPresentable {
var input: TodoListPresentable.Input
var output: TodoListPresentable.Output
private let storeManager: StoreManager
init(input: TodoListPresentable.Input, storeManager: StoreManager) {
self.input = input
self.storeManager = storeManager
self.output = TodoListViewModel.output(storeManager: self.storeManager)
}
}
private extension TodoListViewModel {
static func output(storeManager: StoreManager) -> TodoListPresentable.Output {
let todos = storeManager.fetchTodosFromFirestore()
.map { $0.compactMap { TodoCellViewModel(usingModel: $0) } }
.map { [TodoItemsSection(model: 0, items: $0)] }
.asDriver(onErrorJustReturn: [])
return (
todos: todos, ()
)
}
}
前回と同じような構造ですね。コメントでも書いてある通り、
typealias TodoItemsSection = SectionModel<Int, TodoCellViewPresentable>
の部分は扱いやすくするためです。
続いてoutput関数
ですがmap関数
で型変換をしてあげます。
この時新しいObservableに作り変えられる?(表現があってるのかわからない)そうです。
compactMap
はSwift標準のもので、配列内のnil
を取り除いてくれます。
以下を参照してください。
Swift で map, compactMap, flatMap を使いこなそう
TodoListViewController
TodoListViewController
import UIKit
import RxSwift
import RxCocoa
import RxDataSources
class TodoListViewController: UIViewController, Storyboardable {
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var dismissButton: UIBarButtonItem!
private static let cellId = "TodoCell"
private let dataSources = RxTableViewSectionedReloadDataSource<TodoItemsSection> { (_, tableView, indexPath, item) -> UITableViewCell in
let cell = tableView.dequeueReusableCell(withIdentifier: TodoListViewController.cellId, for: indexPath) as! TodoCell
cell.configure(usingViewModel: item)
return cell
}
private let disposeBag = DisposeBag()
private var viewModel: TodoListPresentable!
private let storeManager = StoreManager()
override func viewDidLoad() {
super.viewDidLoad()
self.viewModel = TodoListViewModel(input: (), storeManager: storeManager)
setupViews()
setupBinding()
}
private func setupViews() {
tableView.register(UINib(nibName: "TodoCell", bundle: nil), forCellReuseIdentifier: TodoListViewController.cellId)
tableView.separatorStyle = .none
}
private func setupBinding() {
self.viewModel.output.todos
.drive(tableView.rx.items(dataSource: self.dataSources))
.disposed(by: disposeBag)
dismissButton.rx.tap.subscribe(onNext: { [weak self] in
self?.dismiss(animated: true)
}).disposed(by: disposeBag)
}
}
import UIKit
import RxSwift
import RxCocoa
import RxDataSources
class TodoListViewController: UIViewController, Storyboardable {
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var dismissButton: UIBarButtonItem!
private static let cellId = "TodoCell"
private let dataSources = RxTableViewSectionedReloadDataSource<TodoItemsSection> { (_, tableView, indexPath, item) -> UITableViewCell in
let cell = tableView.dequeueReusableCell(withIdentifier: TodoListViewController.cellId, for: indexPath) as! TodoCell
cell.configure(usingViewModel: item)
return cell
}
private let disposeBag = DisposeBag()
private var viewModel: TodoListPresentable!
private let storeManager = StoreManager()
override func viewDidLoad() {
super.viewDidLoad()
self.viewModel = TodoListViewModel(input: (), storeManager: storeManager)
setupViews()
setupBinding()
}
private func setupViews() {
tableView.register(UINib(nibName: "TodoCell", bundle: nil), forCellReuseIdentifier: TodoListViewController.cellId)
tableView.separatorStyle = .none
}
private func setupBinding() {
self.viewModel.output.todos
.drive(tableView.rx.items(dataSource: self.dataSources))
.disposed(by: disposeBag)
dismissButton.rx.tap.subscribe(onNext: { [weak self] in
self?.dismiss(animated: true)
}).disposed(by: disposeBag)
}
}
コード自体はそこまで長くないですね。まずは以下のコードからみていきましょう。
private let dataSources = RxTableViewSectionedReloadDataSource<TodoItemsSection> { (_, tableView, indexPath, item) -> UITableViewCell in
let cell = tableView.dequeueReusableCell(withIdentifier: TodoListViewController.cellId, for: indexPath) as! TodoCell
cell.configure(usingViewModel: item)
return cell
}
RxTableViewSectionedReloadDataSource
はRxDataSources
が提供してくれているので導入しておいてください。
<TodoItemsSection>
は先程のTodoListViewModel
でtypealiasしたものですね。
指定なかったら
<SectionModel<Int, TodoCellViewPresentable>>
と書きます。
そしてitem
はTodoCellViewPresentable
が流れてくるのでそれに準拠した型のものになります。
setupBingin関数の
中も特に難しいことはないと思います。
まとめ
part分けする予定もなかった本記事ですが、長くなってしまいました。
また本記事では出てきていないclassなどがあると思いますが、解説は要らないレベルのものになっていますのでGithubをみてください。
github
書く前よりほんの少し理解が進んだかな?という印象です。
もっと勉強して完全に理解したになれるように頑張りたいですねw
Author And Source
この問題について(TodoAppでRxSwift入門[part4]), 我々は、より多くの情報をここで見つけました https://qiita.com/apapapa/items/901f000cd3af697f0d89著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .