UITableView (with RxSwift)
TableView 를 RxSwift 로 그리기!
CollectionView 도 같은 방식으로 작동한다고 한다. (직접 해봐야 하지만.)
기존의 길고 긴 TableView boilier plate code 대신,
cities.bind(to: tableView.rx.items) {
(tableView: UITableView, index: Int, element: String) in
let cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
cell.textLabel?.text = element
return cell
}
한 다섯줄의 간단한 코드로 기본적인 UITableView 를 만들 수 있다!
작동하는 기본적인 방식은, Observable 을 tableView.rx.items (observer) 에 bind 시키는 것.
생성도 간단하지만, 그 외 TableView 관련 Delegate 들도 간단한 것들은 RxCocoa에, section, animation 관련된 것들은 RxDataSourcees ( https://github.com/RxSwiftCommunity/ ) 에 찾아서 보면 있다고 한다.
----------------------------------------------------------------------------------------
어제 찾지 못한 Observable 을 직접 UILabel 등에 반영하는 방법을 찾았다.
someObservable
.bind(to: label.rx.text)
.disposed(by: bag)
이 단순한 코드인데, 해당 코드를 작성하면서 매우 기초적인 내용을 다시 복습할 수 있게 되었다.
Observable : 값을 뱉는 것들
Observer: Observable 을 실시간으로 Observe 하면서, 본인의 값을 변형시킬 수 있는 것들!!
여기서의 func bind 는 observer 를 받는다 (용도가 많아서 자주 헷갈린다.. )
func bind<Observer>(to observers: Observer...) -> Disposable
where Observer : ObserverType, Observer.Element == String?
----------------------------------------------------------------------------------------
//
// TabelViewController.swift
// RxPractice
//
// Created by Mac mini on 2022/09/30.
//
import Foundation
import UIKit
import Then
import SnapKit
import RxSwift
import RxCocoa
class TableViewController: UIViewController {
let ob = PublishSubject<String>()
let bag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
bindTableView()
setupLayout()
}
private func setupLayout() {
// some code ...
}
private let label = UILabel().then {
$0.textColor = .black
$0.backgroundColor = .gray
}
private let tableView = UITableView()
private func bindTableView() {
let cities = Observable.of(["Lisbon", "Copenhagen", "London", "Madrid", "Vienna"])
cities.bind(to: tableView.rx.items) {
(tableView: UITableView, index: Int, element: String) in
let cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
cell.textLabel?.text = element
return cell
}
.disposed(by: bag)
/*
• tableView.rx.items is a binder method operating on observable sequences of
elements (like Observable<[String]>).
• The binding creates an invisible ObserverType object which subscribes to your
sequence, and sets itself as the dataSource and delegate of the table view.
• When a new array of elements is delivered on the observable, the binding reloads
the table view.
• To obtain the cell for each item, RxCocoa calls your closure with details
(and date) for the row being reloaded.
*/
// MARK: - Capture user selection
tableView.rx
.modelSelected(String.self)
.subscribe(onNext: { [weak self] model in
guard let self = self else { return }
self.ob.onNext(model)
})
.disposed(by: bag)
/*
The modelSelected(_:) method returns an observable which emits the model
object (the element represented by the cell) every time the user selects one.
An additional variant — itemSelected() — transports the IndexPath of
the selected item.
modelSelected(_:),modelDeselected(_:),itemSelected,itemDeselectedfire
on item selection.
• modelDeleted(_:) fires on item deletion
(upon tableView:commitEditingStyle:forRowAtIndexPath:).
• itemAccessoryButtonTapped fire on accessory button tap.
• itemInserted, itemDeleted, itemMoved fire on event callbacks
in table edit mode.
• willDisplayCell, didEndDisplayingCell fire every time related
UITableViewDelegate callbacks fire.
These are all simple wrappers around equivalent UITableViewDelegate methods.
*/
ob.asObservable()
.bind(to: label.rx.text)
.disposed(by: bag)
}
}
// Extended support for things such as sections and animations comes with
// RxDataSources https://github.com/RxSwiftCommunity/ RxDataSources,
// an advanced framework found under the umbrella of RxSwiftCommunity organization.