Swift/RxSwift

UITableView (with RxSwift)

iosswift 2022. 9. 30. 23:59

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 를 만들 수 있다! 

작동하는 기본적인 방식은, ObservabletableView.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.