在詳細(xì)介紹 RxSwift
相關(guān)的知識(shí)點(diǎn)之前号显,我想先通過一個(gè)樣例演示下 RxSwift
到底能做什么揽碘,好讓大家能夠?qū)ζ溆幸粋€(gè)直觀的了解。
三涌穆、兩種編程方式的比較樣例
1原叮,效果圖
這里我以最常見的 tableView
數(shù)據(jù)展示功能為例作為演示搬味。后面分別使用傳統(tǒng)寫法,以及使用 RxSwift
響應(yīng)式寫法來實(shí)現(xiàn)预烙,大家可以比較下它們的區(qū)別狸剃。
- ? ? 表格中顯示的是歌曲信息(歌名,以及歌手)
- ? ? 點(diǎn)擊選中任意一個(gè)單元格绩鸣,在控制臺(tái)中打印出對(duì)應(yīng)的歌曲信息。
2,準(zhǔn)備工作
首先我們創(chuàng)建一個(gè) Music
的結(jié)構(gòu)體竞穷,用來保存歌曲名稱鼠哥、歌手名字。此外它還遵循 CustomStringConvertible
協(xié)議,方便我們輸出調(diào)試同衣。
import UIKit
//歌曲結(jié)構(gòu)體
struct Music {
let name: String //歌名
let singer: String //演唱者
init(name: String, singer: String) {
self.name = name
self.singer = singer
}
}
//實(shí)現(xiàn) CustomStringConvertible 協(xié)議,方便輸出調(diào)試
extension Music: CustomStringConvertible {
var description: String {
return "name:\(name) singer:\(singer)"
}
}
3,過去我們會(huì)這么做(傳統(tǒng)式編程)
(1)首先寫一個(gè) ViewModel
- 這里面沒有什么太復(fù)雜的東西贪染,就是生成一個(gè)
UITableView
所使用的數(shù)據(jù)源。
import Foundation
//歌曲列表數(shù)據(jù)源
struct MusicListViewModel {
let data = [
Music(name: "無條件", singer: "陳奕迅"),
Music(name: "你曾是少年", singer: "S.H.E"),
Music(name: "從前的我", singer: "陳潔儀"),
Music(name: "在木星", singer: "樸樹"),
]
}
(2)視圖控制器代碼(ViewController.swift)
- 接著我們?cè)O(shè)置
UITableView
的委托催享,并讓視圖控制器實(shí)現(xiàn)UITableViewDataSource
和UITableViewDelegate
協(xié)議杭隙,及相關(guān)的協(xié)議方法。 - 這個(gè)大家肯定都寫過無數(shù)遍了因妙,也沒什么好講的痰憎。算一下,這里一共需要 43 行代碼攀涵。
import UIKit
import RxSwift
class ViewController: UIViewController {
//tableView對(duì)象
@IBOutlet weak var tableView: UITableView!
//歌曲列表數(shù)據(jù)源
let musicListViewModel = MusicListViewModel()
override func viewDidLoad() {
super.viewDidLoad()
//設(shè)置代理
tableView.dataSource = self
tableView.delegate = self
}
}
extension ViewController: UITableViewDataSource {
//返回單元格數(shù)量
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return musicListViewModel.data.count
}
//返回對(duì)應(yīng)的單元格
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
-> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "musicCell")!
let music = musicListViewModel.data[indexPath.row]
cell.textLabel?.text = music.name
cell.detailTextLabel?.text = music.singer
return cell
}
}
extension ViewController: UITableViewDelegate {
//單元格點(diǎn)擊
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("你選中的歌曲信息【\(musicListViewModel.data[indexPath.row])】")
}
}
4画株,現(xiàn)在使用 RxSwift 進(jìn)行改造(響應(yīng)式編程)
(1)對(duì) ViewModel
做些修改
- 這里我們將
data
屬性變成一個(gè)可觀察序列對(duì)象(Observable Squence)
煞赢,而對(duì)象當(dāng)中的內(nèi)容和我們之前在數(shù)組當(dāng)中所包含的內(nèi)容是完全一樣的丈莺。 - 關(guān)于可觀察序列對(duì)象在后面的文章中我會(huì)詳細(xì)介紹疼电。簡單說就是“序列”可以對(duì)這些數(shù)值進(jìn)行“訂閱
(Subscribe)
”,有點(diǎn)類似于“通知(NotificationCenter)
”
import RxSwift
//歌曲列表數(shù)據(jù)源
struct MusicListViewModel {
let data = Observable.just([
Music(name: "無條件", singer: "陳奕迅"),
Music(name: "你曾是少年", singer: "S.H.E"),
Music(name: "從前的我", singer: "陳潔儀"),
Music(name: "在木星", singer: "樸樹"),
])
}
(2)視圖控制器代碼(ViewController.swift)
- 這里我們不再需要實(shí)現(xiàn)數(shù)據(jù)源和委托協(xié)議了据德。而是寫一些響應(yīng)式代碼鳄乏,讓它們將數(shù)據(jù)和 UITableView 建立綁定關(guān)系跷车。
- 算了下這里我們只需要 31 行代碼,同之前的相比橱野,一下減少了 1/4 代碼量朽缴。而且代碼也更清爽了些。
代碼的簡單說明:
DisposeBag
:作用是Rx
在視圖控制器或者其持有者將要銷毀的時(shí)候水援,自動(dòng)釋法掉綁定在它上面的資源密强。它是通過類似“訂閱處置機(jī)制”方式實(shí)現(xiàn)(類似于NotificationCenter
的removeObserver
)。rx.items(cellIdentifier:)
:這是Rx
基于cellForRowAt
數(shù)據(jù)源方法的一個(gè)封裝蜗元。傳統(tǒng)方式中我們還要有個(gè)numberOfRowsInSection
方法或渤,使用Rx
后就不再需要了(Rx
已經(jīng)幫我們完成了相關(guān)工作)。rx.modelSelected
: 這是Rx
基于UITableView
委托回調(diào)方法didSelectRowAt
的一個(gè)封裝奕扣。
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
//tableView對(duì)象
@IBOutlet weak var tableView: UITableView!
//歌曲列表數(shù)據(jù)源
let musicListViewModel = MusicListViewModel()
//負(fù)責(zé)對(duì)象銷毀
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
//將數(shù)據(jù)源數(shù)據(jù)綁定到tableView上
musicListViewModel.data
.bind(to: tableView.rx.items(cellIdentifier:"musicCell")) { _, music, cell in
cell.textLabel?.text = music.name
cell.detailTextLabel?.text = music.singer
}.disposed(by: disposeBag)
//tableView點(diǎn)擊響應(yīng)
tableView.rx.modelSelected(Music.self).subscribe(onNext: { music in
print("你選中的歌曲信息【\(music)】")
}).disposed(by: disposeBag)
}
}