@TOC
Rxswift 常用的數(shù)據(jù)處理
Target Action
實(shí)例1:
- 傳統(tǒng)代碼
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
func buttonTapped() {
print("button Tapped")
}
- Rxswift代碼
button.rx.tap
.subscribe(onNext: {
print("button Tapped")
})
.disposed(by: disposeBag)
你不需要使用 Target Action,這樣使得代碼邏輯清晰可見。
代理
實(shí)例2:
- 傳統(tǒng)代碼
class ViewController: UIViewController {
...
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
}
}
extension ViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
print("contentOffset: \(scrollView.contentOffset)")
}
}
- Rxswift代碼
class ViewController: UIViewController {
...
override func viewDidLoad() {
super.viewDidLoad()
scrollView.rx.contentOffset
.subscribe(onNext: { contentOffset in
print("contentOffset: \(contentOffset)")
})
.disposed(by: disposeBag)
}
}
Rxswift實(shí)現(xiàn)的代理,你不需要書寫代理的配置代碼,就能獲得想要的結(jié)果。
通知
實(shí)例3:
- 傳統(tǒng)代碼
var ntfObserver: NSObjectProtocol!
override func viewDidLoad() {
super.viewDidLoad()
ntfObserver = NotificationCenter.default.addObserver(
forName: .UIApplicationWillEnterForeground,
object: nil, queue: nil) { (notification) in
print("Application Will Enter Foreground")
}
}
deinit {
NotificationCenter.default.removeObserver(ntfObserver)
}
- Rxswift代碼
NotificationCenter.default.rx.notification(UIResponder.keyboardWillShowNotification)
.subscribe(onNext: { (noti) in
print(noti)
})
.disposed(by: disposeBag)
閉包回調(diào)
實(shí)例4:
- 傳統(tǒng)代碼
URLSession.shared.dataTask(with: URLRequest(url: url)) {
(data, response, error) in
guard error == nil else {
print("Data Task Error: \(error!)")
return
}
guard let data = data else {
print("Data Task Error: unknown")
return
}
print("Data Task Success with count: \(data.count)")
}.resume()
- Rxswift代碼
URLSession.shared.rx.data(request: URLRequest(url: url))
.subscribe(onNext: { data in
print("Data Task Success with count: \(data.count)")
}, onError: { error in
print("Data Task Error: \(error)")
})
.disposed(by: disposeBag)
KVO
實(shí)例5:
- 傳統(tǒng)代碼
- Rxswift代碼
//監(jiān)聽person對象的name的變化
self.person.rx.observeWeakly(String.self, "name")
.subscribe(onNext: { (value) in
print(value as Any)
})
.disposed(by: disposeBag)
手勢
實(shí)例6:
- 傳統(tǒng)代碼
- Rxswift代碼
let disposeBag = DisposeBag()
let tap = UITapGestureRecognizer()
self.label.addGestureRecognizer(tap)
self.label.isUserInteractionEnabled = true
tap.rx.event.subscribe(onNext: { (tap) in
print(tap.view)
})
.disposed(by: disposeBag)
網(wǎng)路請求
實(shí)例7:
- 傳統(tǒng)代碼
- Rxswift代碼
let url = URL(string: "https://www.baidu.com")
URLSession.shared.rx.response(request: URLRequest(url: url!)).subscribe(onNext: { (response,data) in
print(response)
}, onError: { (error) in
print(error)
}, onCompleted: {
}).disposed(by: disposeBag)
定時(shí)器
實(shí)例8:
- 傳統(tǒng)代碼
- Rxswift代碼
let disposeBag = DisposeBag()
var timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
timer.subscribe(onNext: { (num) in
print(num)
})
.disposed(by: disposeBag)
多個(gè)任務(wù)之間有依賴關(guān)系
實(shí)例9:
例如,先通過用戶名密碼取得 Token 然后通過 Token 取得用戶信息
- 傳統(tǒng)代碼
/// 用回調(diào)的方式封裝接口
enum API {
/// 通過用戶名密碼取得一個(gè) token
static func token(username: String, password: String,
success: (String) -> Void,
failure: (Error) -> Void) { ... }
/// 通過 token 取得用戶信息
static func userinfo(token: String,
success: (UserInfo) -> Void,
failure: (Error) -> Void) { ... }
}
/// 通過用戶名和密碼獲取用戶信息
API.token(username: "beeth0ven", password: "987654321",
success: { token in
API.userInfo(token: token,
success: { userInfo in
print("獲取用戶信息成功: \(userInfo)")
},
failure: { error in
print("獲取用戶信息失敗: \(error)")
})
},
failure: { error in
print("獲取用戶信息失敗: \(error)")
})
- Rxswift代碼
/// 用 Rx 封裝接口
enum API {
/// 通過用戶名密碼取得一個(gè) token
static func token(username: String, password: String) -> Observable<String> { ... }
/// 通過 token 取得用戶信息
static func userInfo(token: String) -> Observable<UserInfo> { ... }
}
/// 通過用戶名和密碼獲取用戶信息
API.token(username: "beeth0ven", password: "987654321")
.flatMapLatest(API.userInfo)
.subscribe(onNext: { userInfo in
print("獲取用戶信息成功: \(userInfo)")
}, onError: { error in
print("獲取用戶信息失敗: \(error)")
})
.disposed(by: disposeBag)
等待多個(gè)并發(fā)任務(wù)完成后處理結(jié)果
實(shí)例10:
例如,需要將兩個(gè)網(wǎng)絡(luò)請求合并成一個(gè)
通過 Rx 來實(shí)現(xiàn):
/// 用 Rx 封裝接口
enum API {
/// 取得老師的詳細(xì)信息
static func teacher(teacherId: Int) -> Observable<Teacher> { ... }
/// 取得老師的評論
static func teacherComments(teacherId: Int) -> Observable<[Comment]> { ... }
}
/// 同時(shí)取得老師信息和老師評論
Observable.zip(
API.teacher(teacherId: teacherId),
API.teacherComments(teacherId: teacherId)
).subscribe(onNext: { (teacher, comments) in
print("獲取老師信息成功: \(teacher)")
print("獲取老師評論成功: \(comments.count) 條")
}, onError: { error in
print("獲取老師信息或評論失敗: \(error)")
})
.disposed(by: disposeBag)
這樣你可用寥寥幾行代碼來完成相當(dāng)復(fù)雜的異步操作。
數(shù)據(jù)綁定
實(shí)例11:

在 RxSwift 里有一個(gè)比較重要的概念就是數(shù)據(jù)綁定(訂閱)。就是指將可監(jiān)聽序列綁定到觀察者上:
我們對比一下這兩段代碼:
- 傳統(tǒng)代碼:
將一個(gè)單獨(dú)的圖片設(shè)置到imageView上
let image: UIImage = UIImage(named: ...)
imageView.image = image
- Rx代碼:
let image: Observable<UIImage> = ...
image.bind(to: imageView.rx.image)
Rx代碼:上面這段代碼是將一個(gè)圖片序列 “同步” 到imageView上。這個(gè)序列里面的圖片可以是異步產(chǎn)生的。這里定義的 image 就是上圖中藍(lán)色部分(可監(jiān)聽序列),imageView.rx.image就是上圖中橙色部分(觀察者)。而這種 “同步機(jī)制” 就是數(shù)據(jù)綁定(訂閱)。
Rxswift UI 用法
UILabel
實(shí)例30:
- 傳統(tǒng)代碼
- Rxswift代碼
- Rxswift簡單使用UILabel
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag()
override func viewDidLoad() {
//創(chuàng)建文本標(biāo)簽
let label = UILabel(frame:CGRect(x:20, y:40, width:300, height:100))
self.view.addSubview(label)
//創(chuàng)建一個(gè)計(jì)時(shí)器(每0.1秒發(fā)送一個(gè)索引數(shù))
let timer = Observable<Int>.interval(0.1, scheduler: MainScheduler.instance)
//將已過去的時(shí)間格式化成想要的字符串,并綁定到label上
timer.map{ String(format: "%0.2d:%0.2d.%0.1d",
arguments: [($0 / 600) % 600, ($0 % 600 ) / 10, $0 % 10]) }
.bind(to: label.rx.text)
.disposed(by: disposeBag)
}
}
- UILabel富文本 :將數(shù)據(jù)綁定到 attributedText 屬性上
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag()
override func viewDidLoad() {
//創(chuàng)建文本標(biāo)簽
let label = UILabel(frame:CGRect(x:20, y:40, width:300, height:100))
self.view.addSubview(label)
//創(chuàng)建一個(gè)計(jì)時(shí)器(每0.1秒發(fā)送一個(gè)索引數(shù))
let timer = Observable<Int>.interval(0.1, scheduler: MainScheduler.instance)
//將已過去的時(shí)間格式化成想要的字符串,并綁定到label上
timer.map(formatTimeInterval)
.bind(to: label.rx.attributedText)
.disposed(by: disposeBag)
}
//將數(shù)字轉(zhuǎn)成對應(yīng)的富文本
func formatTimeInterval(ms: NSInteger) -> NSMutableAttributedString {
let string = String(format: "%0.2d:%0.2d.%0.1d",
arguments: [(ms / 600) % 600, (ms % 600 ) / 10, ms % 10])
//富文本設(shè)置
let attributeString = NSMutableAttributedString(string: string)
//從文本0開始6個(gè)字符字體HelveticaNeue-Bold,16號
attributeString.addAttribute(NSAttributedStringKey.font,
value: UIFont(name: "HelveticaNeue-Bold", size: 16)!,
range: NSMakeRange(0, 5))
//設(shè)置字體顏色
attributeString.addAttribute(NSAttributedStringKey.foregroundColor,
value: UIColor.white, range: NSMakeRange(0, 5))
//設(shè)置文字背景顏色
attributeString.addAttribute(NSAttributedStringKey.backgroundColor,
value: UIColor.orange, range: NSMakeRange(0, 5))
return attributeString
}
}
UIButton
實(shí)例40:
- 傳統(tǒng)代碼
self.button.addTarget(self, action:#selector(buttonTapped(sender:)), for: UIControlEvents.touchUpInside)
@objc func buttonTapped(sender:UIButton?){
}
- Rxswift代碼
let disposeBag = DisposeBag()
//由于tap事件里點(diǎn)擊事件用的最多,所以RX默認(rèn)的tap就是點(diǎn)擊事件
self.button.rx.tap
.subscribe(onNext: { () in
print("點(diǎn)擊來了")
})
.disposed(by: disposeBag)
//RXSwift監(jiān)聽按鈕除了點(diǎn)擊外的事件:
self.button.rx.controlEvent(.touchUpOutside).subscribe(onNext: { () in
})
.disposed(by: disposeBag)
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag()
@IBOutlet weak var button: UIButton!
override func viewDidLoad() {
//按鈕點(diǎn)擊響應(yīng)1
button.rx.tap
.subscribe(onNext: { [weak self] in
self?.showMessage("按鈕被點(diǎn)擊")
})
.disposed(by: disposeBag)
//按鈕點(diǎn)擊響應(yīng)2
button.rx.tap
.bind { [weak self] in
self?.showMessage("按鈕被點(diǎn)擊")
}
.disposed(by: disposeBag)
//
}
//按鈕標(biāo)題(title)的綁定
func test1() {
//創(chuàng)建一個(gè)計(jì)時(shí)器(每1秒發(fā)送一個(gè)索引數(shù))
let timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
//根據(jù)索引數(shù)拼接最新的標(biāo)題,并綁定到button上
timer.map{"計(jì)數(shù)\($0)"}
.bind(to: button.rx.title(for: .normal))
.disposed(by: disposeBag)
}
//按鈕富文本標(biāo)題(attributedTitle)的綁定
func test2() {
//創(chuàng)建一個(gè)計(jì)時(shí)器(每1秒發(fā)送一個(gè)索引數(shù))
let timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
//將已過去的時(shí)間格式化成想要的字符串,并綁定到button上
timer.map(formatTimeInterval)
.bind(to: button.rx.attributedTitle())
.disposed(by: disposeBag)
}
//按鈕圖標(biāo)(image)的綁定
func test3() {
//創(chuàng)建一個(gè)計(jì)時(shí)器(每1秒發(fā)送一個(gè)索引數(shù))
let timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
//根據(jù)索引數(shù)選擇對應(yīng)的按鈕圖標(biāo),并綁定到button上
timer.map({
let name = $0%2 == 0 ? "back" : "forward"
return UIImage(named: name)!
})
.bind(to: button.rx.image())
.disposed(by: disposeBag)
}
//按鈕背景圖片(backgroundImage)的綁定
func test4() {
//創(chuàng)建一個(gè)計(jì)時(shí)器(每1秒發(fā)送一個(gè)索引數(shù))
let timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
//根據(jù)索引數(shù)選擇對應(yīng)的按鈕背景圖,并綁定到button上
timer.map{ UIImage(named: "\($0%2)")! }
.bind(to: button.rx.backgroundImage())
.disposed(by: disposeBag)
}
//將數(shù)字轉(zhuǎn)成對應(yīng)的富文本
func formatTimeInterval(ms: NSInteger) -> NSMutableAttributedString {
let string = String(format: "%0.2d:%0.2d.%0.1d",
arguments: [(ms / 600) % 600, (ms % 600 ) / 10, ms % 10])
//富文本設(shè)置
let attributeString = NSMutableAttributedString(string: string)
//從文本0開始6個(gè)字符字體HelveticaNeue-Bold,16號
attributeString.addAttribute(NSAttributedStringKey.font,
value: UIFont(name: "HelveticaNeue-Bold", size: 16)!,
range: NSMakeRange(0, 5))
//設(shè)置字體顏色
attributeString.addAttribute(NSAttributedStringKey.foregroundColor,
value: UIColor.white, range: NSMakeRange(0, 5))
//設(shè)置文字背景顏色
attributeString.addAttribute(NSAttributedStringKey.backgroundColor,
value: UIColor.orange, range: NSMakeRange(0, 5))
return attributeString
}
//顯示消息提示框
func showMessage(_ text: String) {
let alertController = UIAlertController(title: text, message: nil, preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "確定", style: .cancel, handler: nil)
alertController.addAction(cancelAction)
self.present(alertController, animated: true, completion: nil)
}
}
UIBarButtonItem
實(shí)例50:
- 傳統(tǒng)代碼
- Rxswift代碼
UISwitch
實(shí)例60:
- 傳統(tǒng)代碼
- Rxswift代碼
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
//分段選擇控件
@IBOutlet weak var segmented: UISegmentedControl!
//圖片顯示控件
@IBOutlet weak var imageView: UIImageView!
let disposeBag = DisposeBag()
override func viewDidLoad() {
//創(chuàng)建一個(gè)當(dāng)前需要顯示的圖片的可觀察序列
let showImageObservable: Observable<UIImage> =
segmented.rx.selectedSegmentIndex.asObservable().map {
let images = ["js.png", "php.png", "react.png"]
return UIImage(named: images[$0])!
}
//把需要顯示的圖片綁定到 imageView 上
showImageObservable.bind(to: imageView.rx.image)
.disposed(by: disposeBag)
}
func test1() {
switch1.rx.isOn.asObservable()
.subscribe(onNext: {
print("當(dāng)前開關(guān)狀態(tài):\($0)")
})
.disposed(by: disposeBag)
}
func test2() {
switch1.rx.isOn
.bind(to: button1.rx.isEnabled)
.disposed(by: disposeBag)
}
}
UISegmentedControl
實(shí)例70:
- 傳統(tǒng)代碼
- Rxswift代碼
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
//分段選擇控件
@IBOutlet weak var segmented: UISegmentedControl!
//圖片顯示控件
@IBOutlet weak var imageView: UIImageView!
let disposeBag = DisposeBag()
override func viewDidLoad() {
//創(chuàng)建一個(gè)當(dāng)前需要顯示的圖片的可觀察序列
let showImageObservable: Observable<UIImage> =
segmented.rx.selectedSegmentIndex.asObservable().map {
let images = ["js.png", "php.png", "react.png"]
return UIImage(named: images[$0])!
}
//把需要顯示的圖片綁定到 imageView 上
showImageObservable.bind(to: imageView.rx.image)
.disposed(by: disposeBag)
}
func test1() {
segmented.rx.selectedSegmentIndex.asObservable()
.subscribe(onNext: {
print("當(dāng)前項(xiàng):\($0)")
})
.disposed(by: disposeBag)
}
}
UIActivityIndicatorView
實(shí)例80:
- 傳統(tǒng)代碼
- Rxswift代碼
UITextField
實(shí)例90:UITextField使用Rxswift的基本用法
- 傳統(tǒng)代碼
- Rxswift代碼
self.textFiled.rx.text.orEmpty
.subscribe(onNext: { (text) in
print(text)
})
.disposed(by: disposeBag)
// textfiled綁定Button的文字
self.textFiled.rx.text
.bind(to: self.button.rx.title())
.disposed(by: disposeBag)
實(shí)例91:Rxswift監(jiān)聽單個(gè) textField 內(nèi)容的變化
- Rxswift代碼
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag()
override func viewDidLoad() {
//創(chuàng)建文本輸入框
let textField = UITextField(frame: CGRect(x:10, y:80, width:200, height:30))
textField.borderStyle = UITextBorderStyle.roundedRect
self.view.addSubview(textField)
//當(dāng)文本框內(nèi)容改變時(shí),將內(nèi)容輸出到控制臺上
textField.rx.text.orEmpty.asObservable()
.subscribe(onNext: {
print("您輸入的是:\($0)")
})
.disposed(by: disposeBag)
//當(dāng)文本框內(nèi)容改變時(shí),將內(nèi)容輸出到控制臺上
textField.rx.text.orEmpty.changed
.subscribe(onNext: {
print("您輸入的是:\($0)")
})
.disposed(by: disposeBag)
}
}
實(shí)例92:Rxswift將textField的內(nèi)容綁定到其他控件上
- Rxswift代碼
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag()
override func viewDidLoad() {
//創(chuàng)建文本輸入框
let inputField = UITextField(frame: CGRect(x:10, y:80, width:200, height:30))
inputField.borderStyle = UITextBorderStyle.roundedRect
self.view.addSubview(inputField)
//創(chuàng)建文本輸出框
let outputField = UITextField(frame: CGRect(x:10, y:150, width:200, height:30))
outputField.borderStyle = UITextBorderStyle.roundedRect
self.view.addSubview(outputField)
//創(chuàng)建文本標(biāo)簽
let label = UILabel(frame:CGRect(x:20, y:190, width:300, height:30))
self.view.addSubview(label)
//創(chuàng)建按鈕
let button:UIButton = UIButton(type:.system)
button.frame = CGRect(x:20, y:230, width:40, height:30)
button.setTitle("提交", for:.normal)
self.view.addSubview(button)
//當(dāng)文本框內(nèi)容改變
let input = inputField.rx.text.orEmpty.asDriver() // 將普通序列轉(zhuǎn)換為 Driver
.throttle(0.3) //在主線程中操作,0.3秒內(nèi)值若多次改變,取最后一次
//內(nèi)容綁定到另一個(gè)輸入框中
input.drive(outputField.rx.text)
.disposed(by: disposeBag)
//內(nèi)容綁定到文本標(biāo)簽中
input.map{ "當(dāng)前字?jǐn)?shù):\($0.count)" }
.drive(label.rx.text)
.disposed(by: disposeBag)
//根據(jù)內(nèi)容字?jǐn)?shù)決定按鈕是否可用
input.map{ $0.count > 5 }
.drive(button.rx.isEnabled)
.disposed(by: disposeBag)
}
}
實(shí)例93:Rxswift同時(shí)監(jiān)聽多個(gè) textField 內(nèi)容的變化
- Rxswift代碼
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag()
@IBOutlet weak var textField1: UITextField!
@IBOutlet weak var textField2: UITextField!
@IBOutlet weak var label: UILabel!
override func viewDidLoad() {
Observable.combineLatest(textField1.rx.text.orEmpty, textField2.rx.text.orEmpty) {
textValue1, textValue2 -> String in
return "你輸入的號碼是:\(textValue1)-\(textValue2)"
}
.map { $0 }
.bind(to: label.rx.text)
.disposed(by: disposeBag)
}
}
實(shí)例94:Rxswift實(shí)現(xiàn)textField事件監(jiān)聽
通過 rx.controlEvent 可以監(jiān)聽輸入框的各種事件,且多個(gè)事件狀態(tài)可以自由組合。除了各種 UI 控件都有的 touch 事件外,輸入框還有如下幾個(gè)獨(dú)有的事件:
editingDidBegin:開始編輯(開始輸入內(nèi)容)
editingChanged:輸入內(nèi)容發(fā)生改變
editingDidEnd:結(jié)束編輯
editingDidEndOnExit:按下 return 鍵結(jié)束編輯
allEditingEvents:包含前面的所有編輯相關(guān)事件
- Rxswift代碼
textField.rx.controlEvent([.editingDidBegin]) //狀態(tài)可以組合
.asObservable()
.subscribe(onNext: { _ in
print("開始編輯內(nèi)容!")
}).disposed(by: disposeBag)
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
//用戶名輸入框
@IBOutlet weak var username: UITextField!
//密碼輸入框
@IBOutlet weak var password: UITextField!
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
//在用戶名輸入框中按下 return 鍵
username.rx.controlEvent(.editingDidEndOnExit).subscribe(onNext: {
[weak self] (_) in
self?.password.becomeFirstResponder()
}).disposed(by: disposeBag)
//在密碼輸入框中按下 return 鍵
password.rx.controlEvent(.editingDidEndOnExit).subscribe(onNext: {
[weak self] (_) in
self?.password.resignFirstResponder()
}).disposed(by: disposeBag)
}
}
實(shí)例95:Rxswift實(shí)現(xiàn)textField事件監(jiān)聽
- Rxswift代碼
UITextView
實(shí)例100:
- 傳統(tǒng)代碼
- Rxswift代碼
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag()
@IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
//開始編輯響應(yīng)
textView.rx.didBeginEditing
.subscribe(onNext: {
print("開始編輯")
})
.disposed(by: disposeBag)
//結(jié)束編輯響應(yīng)
textView.rx.didEndEditing
.subscribe(onNext: {
print("結(jié)束編輯")
})
.disposed(by: disposeBag)
//內(nèi)容發(fā)生變化響應(yīng)
textView.rx.didChange
.subscribe(onNext: {
print("內(nèi)容發(fā)生改變")
})
.disposed(by: disposeBag)
//選中部分變化響應(yīng)
textView.rx.didChangeSelection
.subscribe(onNext: {
print("選中部分發(fā)生變化")
})
.disposed(by: disposeBag)
}
}
UITableView
- 傳統(tǒng)Swift使用UITableView
實(shí)例110:
//歌曲結(jié)構(gòu)體
struct Music {
let name: String //歌名
let singer: String //演唱者
init(name: String, singer: String) {
self.name = name
self.singer = singer
}
}
//歌曲列表數(shù)據(jù)源
struct MusicListViewModel {
let data = [
Music(name: "無條件", singer: "陳奕迅"),
Music(name: "你曾是少年", singer: "S.H.E"),
Music(name: "從前的我", singer: "陳潔儀"),
Music(name: "在木星", singer: "樸樹"),
]
}
class ViewController: UIViewController {
//tableView對象
@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
}
//返回對應(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])】")
}
}
- Rxswift 的UITableView
實(shí)例111:
/*這里我們將 data 屬性變成一個(gè)可觀察序列對象(Observable Squence),
而對象當(dāng)中的內(nèi)容和我們之前在數(shù)組當(dāng)中所包含的內(nèi)容是完全一樣的。
*/
//歌曲列表數(shù)據(jù)源
struct MusicListViewModel {
let data = Observable.just([
Music(name: "無條件", singer: "陳奕迅"),
Music(name: "你曾是少年", singer: "S.H.E"),
Music(name: "從前的我", singer: "陳潔儀"),
Music(name: "在木星", singer: "樸樹"),
])
}
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
//tableView對象
@IBOutlet weak var tableView: UITableView!
//歌曲列表數(shù)據(jù)源
let musicListViewModel = MusicListViewModel()
//負(fù)責(zé)對象銷毀
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
//將數(shù)據(jù)源數(shù)據(jù)綁定到tableView上
musicListViewModel.data
.bind(to:
/*
rx.items(cellIdentifier:):這是 Rx 基于 cellForRowAt 數(shù)據(jù)源方法的一個(gè)封裝。
傳統(tǒng)方式中我們還要有個(gè) numberOfRowsInSection 方法,
使用 Rx 后就不再需要了(Rx 已經(jīng)幫我們完成了相關(guān)工作)。
*/
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)
/*
rx.modelSelected: 這是 Rx 基于 UITableView委托回調(diào)方法 didSelectRowAt 的一個(gè)封裝。
*/ tableView.rx.modelSelected(Music.self).subscribe(onNext: { music in
print("你選中的歌曲信息【\(music)】")
}).disposed(by: disposeBag)
/*DisposeBag:作用是 Rx 在視圖控制器或者其持有者將要銷毀的時(shí)候,
自動(dòng)釋法掉綁定在它上面的資源。
它是通過類似“訂閱處置機(jī)制”方式實(shí)現(xiàn)(類似于 NotificationCenter 的 removeObserver)。*/
}
}
UICollectionView
實(shí)例120:
- 傳統(tǒng)代碼
- Rxswift代碼
UIPickerView
實(shí)例130:
- 傳統(tǒng)代碼
- Rxswift代碼
UIDatePicker
實(shí)例140:
- 傳統(tǒng)代碼
- Rxswift代碼
UISlider
實(shí)例150:
- 傳統(tǒng)代碼
- Rxswift代碼
UIStepper
實(shí)例160:
- 傳統(tǒng)代碼
- Rxswift代碼