RxSwift(七)Rxswift對比swift用法

@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

image

在 RxSwift 里有一個(gè)比較重要的概念就是數(shù)據(jù)綁定(訂閱)。就是指將可監(jiān)聽序列綁定到觀察者上:

我們對比一下這兩段代碼:

  1. 傳統(tǒng)代碼:

將一個(gè)單獨(dú)的圖片設(shè)置到imageView上

let image: UIImage = UIImage(named: ...)
imageView.image = image
  1. 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代碼
  1. 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)
    }
}
  1. 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代碼

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • @TOC Rxswift 常用的數(shù)據(jù)處理 通知 實(shí)例1: 傳統(tǒng)代碼 Rxswift代碼 KVO 實(shí)例2: 傳統(tǒng)代碼...
    孔雨露閱讀 1,105評論 1 6
  • 概述 RxSwift顧名思義是Swift的一種框架,您或許曾經(jīng)聽說過「響應(yīng)式編程」(Reactive Progra...
    Mr大喵喵閱讀 1,998評論 3 4
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,663評論 1 32
  • 前言 在之前用Objective-C語言做項(xiàng)目的時(shí)候,我習(xí)慣性的會(huì)利用MVVM模式去架構(gòu)項(xiàng)目,在框架Reactiv...
    Tangentw閱讀 21,398評論 32 124
  • “哪日王上想要這天下了,我就告訴王上我想要什么?!?藍(lán)衣男子怔怔地看著朱衣男子離去的背影,久久不曾言語,只覺得痛入...
    云十一書33閱讀 3,193評論 0 11

友情鏈接更多精彩內(nèi)容