使用 RXSwift 構建 UITableView

Swift Version:5.0 
RXSwift Version:5.0
複製代碼

本文介紹的是如何使用 RX 構建 UITableView,需對 Swift 有基礎的瞭解。共 1100 字,閱讀需 10 min。git

先說一下構建的主要步驟,這樣你們能更好的理解代碼。github

使用 RXSwift 構建 UITableView 的步驟 swift

  1. 構建 Observable 類型的數據源
  2. 將數據源與 tableView 綁定
  3. 綁定 tableView 的事件(如:cell 的點擊事件)
  4. 設置 tableView Delegate/DataSource 的代理方法(根據需求,非必要)

準備工做

在咱們開始以前,咱們須要在項目中集成 RXSwift,具體步驟可參見 RXSwift。成功集成以後,咱們須要在要使用 RXSwift 的文件中導入它:bash

import RxSwift
複製代碼

接着,咱們要建立一個 DisposeBag 類型的全局變量(必定要是全局變量):閉包

let disposeBag = DisposeBag()
複製代碼

關於 DisposeBag 的做用: DisposeBag 對於 RX 至關於 ARC 對於 iOS,即它是 RX 管理對象內存的一種方式。異步

最後,將須要使用的 cell 進行註冊:async

tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
複製代碼

OK,到如今爲止,咱們已經完成了全部的準備工做。接下來,咱們能夠根據上面的步驟來構建 tableView 了。ide

構建 Observable 類型的數據源

首先,咱們須要構建 Observable 類型的數據源。至於爲何要構建 Observable 類型的數據,咱們能夠從 RXSwift 的文檔上一探究竟。ui

它的文檔上是這麼寫的:Every Observable sequence is just a sequence. The key advantage for an Observable vs Swift's Sequence is that it can also receive elements asynchronously。這句話的意思是說,可觀察序列和 Swift 的原生序列本質上是同樣的,但它們有一個最主要的不一樣,那就是可觀察序列能夠異步接受元素spa

經過下面的代碼建立 Observable 類型的數據源:

let texts = ["Objective-C", "Swift", "RXSwift"]
let textsObservable = Observable.from(optional: texts)
複製代碼

此時,你用 option 鍵查看 textsObservable 屬性的類型,應該顯示的是 Observable<String>

數據源類型

可供使用的數據源已經構建完成,接下來須要將數據源與 tableView 綁定。

將數據源與 tableView 綁定

經過下面代碼進行綁定(不要忘記最後的 .disposed(by: disposeBag) ):

textsObservable.bind(to: tableView.rx
    .items(cellIdentifier: "Cell", cellType: UITableViewCell.self)) { (row, text, cell) in
        cell.textLabel?.text = text
    }
    .disposed(by: disposeBag)
複製代碼

在綁定方法的閉包中,咱們須要定義三個變量,三個變量分別有如下含義:

  • 第一個變量爲當前cell所處的行數,即:indexPath.row
  • 第二個變量爲可觀察序列在當前行數索引的元素,即:texts[row]
  • 第三個變量爲當前cell

閉包底層實現

綁定 tableView 的事件

經過下面代碼進行綁定(cell 的點擊事件):

tableView.rx.itemSelected.bind { (indexPath) in
        print(indexPath)
    }
    .disposed(by: disposeBag)
複製代碼

一樣,不要忘記最後的 disposed 。

到這裏,咱們就完成了經過 RX 構建一個簡單的 tableView 。若是你對 tableView 還有一些自定義的需求,可經過第四步驟完成。

設置 tableView Delegate/DataSource 的代理方法

經過下面的代碼設置代理:

tableView.rx.setDelegate(self).disposed(by: disposeBag)
tableView.rx.setDataSource(self).disposed(by: disposeBag)
複製代碼

而後,你就能夠實現相關的代理方法來進行自定義了,以設置高度舉例:

extension ALGExploreDetailVC: UITableViewDelegate {
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 100
    }
}
複製代碼

注意:若是你不須要使用 UITableViewDelegate/UITableViewDataSource 的委託方法的話,你是能夠不寫的。

// 不使用 RX 的話,須要實現代理方法
tableView.delegate = self
tableView.dataSource = self
extension ViewController: UITableViewDelegate, UITableViewDataSource {
    ....
}

// 使用 RX 
// 綁定便可,不需寫上面的代碼
textsObservable.bind(to: tableView.rx
    .items(cellIdentifier: "Cell", cellType: UITableViewCell.self)) { (row, text, cell) in
        cell.textLabel?.text = "\(text)"
    }
    .disposed(by: disposeBag)
複製代碼

若是使用 RX 綁定了 tableView ,再使用下面的代碼就不對了,咱們需使用 RX 設置代理的方法。

tableView.delegate = self
複製代碼

總結

  • 使用 RX 可使代碼簡潔,易讀
  • 使用 RX 語句後需調用 .disposed(by: disposeBag) ,釋放內存

完整代碼

import UIKit
import RxSwift

class TestViewController: UIViewController {
    var tableView = UITableView(frame: .zero)
    let kCellHeight: CGFloat = 40
    let disposeBag = DisposeBag()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.white
        setupSubviews()
    }
}

extension TestViewController {
    func setupSubviews() {
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
        view.addSubview(tableView)
        
        tableView.translatesAutoresizingMaskIntoConstraints = false
        tableView.safeEdges(to: view)
        //1.建立可觀察數據源
        let texts = ["Objective-C", "Swift", "RXSwift"]
        let textsObservable = Observable.from(optional: texts)
        //2. 將數據源與 tableView 綁定
        textsObservable.bind(to: tableView.rx
            .items(cellIdentifier: "Cell", cellType: UITableViewCell.self)) { (row, text, cell) in
                cell.textLabel?.text = text
            }
            .disposed(by: disposeBag)
        //3. 綁定 tableView 的事件
        tableView.rx.itemSelected.bind { (indexPath) in
                print(indexPath)
            }
            .disposed(by: disposeBag)
        
        //4. 設置 tableView Delegate/DataSource 的代理方法
        tableView.rx.setDelegate(self).disposed(by: disposeBag)
    }
}

extension TestViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 100
    }
}
複製代碼

參考

相關文章
相關標籤/搜索