RxSwift(七)Rxswift對比swift用法

Rxswift(一)函數響應式編程思想php

RxSwift (二)序列核心邏輯分析react

RxSwift (三)Observable的建立,訂閱,銷燬編程

RxSwift(四)高階函數swift

RxSwift(五)(Rxswift對比swift,oc用法)數組

Rxswift (六)銷燬者Dispose源碼分析markdown

RxSwift(七)Rxswift對比swift用法網絡

RxSwift (十) 基礎使用篇 1- 序列,訂閱,銷燬閉包

RxSwift學習之十二 (基礎使用篇 3- UI控件擴展)併發

@TOCapp

Rxswift 經常使用的數據處理

Target Action

實例1

  • 傳統代碼
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,這樣使得代碼邏輯清晰可見。

代理

實例2

  • 傳統代碼
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實現的代理,你不須要書寫代理的配置代碼,就能得到想要的結果。

通知

實例3

  • 傳統代碼
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)
複製代碼

閉包回調

實例4

  • 傳統代碼
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

實例5

  • 傳統代碼
複製代碼
  • Rxswift代碼
//監聽person對象的name的變化
 self.person.rx.observeWeakly(String.self, "name")
            .subscribe(onNext: { (value) in
                print(value as Any)
            })
            .disposed(by: disposeBag)
複製代碼

手勢

實例6

  • 傳統代碼
複製代碼
  • 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)
複製代碼

網路請求

實例7

  • 傳統代碼
複製代碼
  • 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)
複製代碼

定時器

實例8

  • 傳統代碼
複製代碼
  • Rxswift代碼
let disposeBag = DisposeBag()
var timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
        timer.subscribe(onNext: { (num) in
            print(num)
        })
        .disposed(by: disposeBag)
複製代碼

多個任務之間有依賴關係

實例9: 例如,先經過用戶名密碼取得 Token 而後經過 Token 取得用戶信息

  • 傳統代碼
/// 用回調的方式封裝接口
enum API {

    /// 經過用戶名密碼取得一個 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 {

    /// 經過用戶名密碼取得一個 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)
複製代碼

等待多個併發任務完成後處理結果

實例10: 例如,須要將兩個網絡請求合併成一個

經過 Rx 來實現:

/// 用 Rx 封裝接口
enum API {

    /// 取得老師的詳細信息
    static func teacher(teacherId: Int) -> Observable<Teacher> { ... }

    /// 取得老師的評論
    static func teacherComments(teacherId: Int) -> Observable<[Comment]> { ... }
}

/// 同時取得老師信息和老師評論
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)
複製代碼

這樣你可用寥寥幾行代碼來完成至關複雜的異步操做。

數據綁定

實例11

image
在 RxSwift 裏有一個比較重要的概念就是數據綁定(訂閱)。就是指將可監聽序列綁定到觀察者上:

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

  1. 傳統代碼:

將一個單獨的圖片設置到imageView上

let image: UIImage = UIImage(named: ...)
imageView.image = image
複製代碼
  1. Rx代碼:
let image: Observable<UIImage> = ...
image.bind(to: imageView.rx.image)
複製代碼

Rx代碼:上面這段代碼是將一個圖片序列 「同步」 到imageView上。這個序列裏面的圖片能夠是異步產生的。這裏定義的 image 就是上圖中藍色部分(可監聽序列),imageView.rx.image就是上圖中橙色部分(觀察者)。而這種 「同步機制」 就是數據綁定(訂閱)。

Rxswift UI 用法

UILabel

實例30

  • 傳統代碼
複製代碼
  • Rxswift代碼
  1. Rxswift簡單使用UILabel
import UIKit
import RxSwift
import RxCocoa
 
class ViewController: UIViewController {
     
    let disposeBag = DisposeBag()
     
    override func viewDidLoad() {
         
        //建立文本標籤
        let label = UILabel(frame:CGRect(x:20, y:40, width:300, height:100))
        self.view.addSubview(label)
         
        //建立一個計時器(每0.1秒發送一個索引數)
        let timer = Observable<Int>.interval(0.1, scheduler: MainScheduler.instance)
         
        //將已過去的時間格式化成想要的字符串,並綁定到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富文本 :將數據綁定到 attributedText 屬性上
import UIKit
import RxSwift
import RxCocoa
 
class ViewController: UIViewController {
     
    let disposeBag = DisposeBag()
     
    override func viewDidLoad() {
         
        //建立文本標籤
        let label = UILabel(frame:CGRect(x:20, y:40, width:300, height:100))
        self.view.addSubview(label)
         
        //建立一個計時器(每0.1秒發送一個索引數)
        let timer = Observable<Int>.interval(0.1, scheduler: MainScheduler.instance)
         
        //將已過去的時間格式化成想要的字符串,並綁定到label上
        timer.map(formatTimeInterval)
        .bind(to: label.rx.attributedText)
        .disposed(by: disposeBag)
    }
     
    //將數字轉成對應的富文本
    func formatTimeInterval(ms: NSInteger) -> NSMutableAttributedString {
        let string = String(format: "%0.2d:%0.2d.%0.1d",
                         arguments: [(ms / 600) % 600, (ms % 600 ) / 10, ms % 10])
        //富文本設置
        let attributeString = NSMutableAttributedString(string: string)
        //從文本0開始6個字符字體HelveticaNeue-Bold,16號
        attributeString.addAttribute(NSAttributedStringKey.font,
                                     value: UIFont(name: "HelveticaNeue-Bold", size: 16)!,
                                     range: NSMakeRange(0, 5))
        //設置字體顏色
        attributeString.addAttribute(NSAttributedStringKey.foregroundColor,
                                     value: UIColor.white, range: NSMakeRange(0, 5))
        //設置文字背景顏色
        attributeString.addAttribute(NSAttributedStringKey.backgroundColor,
                                     value: UIColor.orange, range: NSMakeRange(0, 5))
        return attributeString
    }
}
複製代碼

UIButton

實例40

  • 傳統代碼
self.button.addTarget(self, action:#selector(buttonTapped(sender:)), for: UIControlEvents.touchUpInside)
    @objc func buttonTapped(sender:UIButton?){
        
    }
複製代碼
  • Rxswift代碼
let disposeBag = DisposeBag()
 //因爲tap事件裏點擊事件用的最多,因此RX默認的tap就是點擊事件
 self.button.rx.tap
            .subscribe(onNext: { () in
                print("點擊來了")
            })
            .disposed(by: disposeBag)



   //RXSwift監聽按鈕除了點擊外的事件:
    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() {
        //按鈕點擊響應1
        button.rx.tap
            .subscribe(onNext: { [weak self] in
                self?.showMessage("按鈕被點擊")
            })
            .disposed(by: disposeBag)

        //按鈕點擊響應2
        button.rx.tap
             .bind { [weak self] in
             self?.showMessage("按鈕被點擊")
               }
               .disposed(by: disposeBag)

//
    }

//按鈕標題(title)的綁定
func test1() {
//建立一個計時器(每1秒發送一個索引數)
let timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
 
//根據索引數拼接最新的標題,並綁定到button上
timer.map{"計數\($0)"}
    .bind(to: button.rx.title(for: .normal))
    .disposed(by: disposeBag)
}

//按鈕富文本標題(attributedTitle)的綁定
func test2() {
 //建立一個計時器(每1秒發送一個索引數)
        let timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
         
        //將已過去的時間格式化成想要的字符串,並綁定到button上
        timer.map(formatTimeInterval)
            .bind(to: button.rx.attributedTitle())
            .disposed(by: disposeBag)
}

//按鈕圖標(image)的綁定
func test3() {
//建立一個計時器(每1秒發送一個索引數)
let timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
 
//根據索引數選擇對應的按鈕圖標,並綁定到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() {
//建立一個計時器(每1秒發送一個索引數)
let timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
 
//根據索引數選擇對應的按鈕背景圖,並綁定到button上
timer.map{ UIImage(named: "\($0%2)")! }
    .bind(to: button.rx.backgroundImage())
    .disposed(by: disposeBag)
}



//將數字轉成對應的富文本
    func formatTimeInterval(ms: NSInteger) -> NSMutableAttributedString {
        let string = String(format: "%0.2d:%0.2d.%0.1d",
                            arguments: [(ms / 600) % 600, (ms % 600 ) / 10, ms % 10])
        //富文本設置
        let attributeString = NSMutableAttributedString(string: string)
        //從文本0開始6個字符字體HelveticaNeue-Bold,16號
        attributeString.addAttribute(NSAttributedStringKey.font,
                                     value: UIFont(name: "HelveticaNeue-Bold", size: 16)!,
                                     range: NSMakeRange(0, 5))
        //設置字體顏色
        attributeString.addAttribute(NSAttributedStringKey.foregroundColor,
                                     value: UIColor.white, range: NSMakeRange(0, 5))
        //設置文字背景顏色
        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

實例50

  • 傳統代碼
複製代碼
  • Rxswift代碼
複製代碼

UISwitch

實例60

  • 傳統代碼
複製代碼
  • 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() {
        //建立一個當前須要顯示的圖片的可觀察序列
        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("當前開關狀態:\($0)")
    })
    .disposed(by: disposeBag)
}

func test2() {
switch1.rx.isOn
    .bind(to: button1.rx.isEnabled)
    .disposed(by: disposeBag)
}
}
複製代碼

UISegmentedControl

實例70

  • 傳統代碼
複製代碼
  • 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() {
        //建立一個當前須要顯示的圖片的可觀察序列
        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("當前項:\($0)")
    })
    .disposed(by: disposeBag)
}
}

複製代碼

UIActivityIndicatorView

實例80

  • 傳統代碼
複製代碼
  • Rxswift代碼
複製代碼

UITextField

實例90:UITextField使用Rxswift的基本用法

  • 傳統代碼
複製代碼
  • 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)
複製代碼

實例91:Rxswift監聽單個 textField 內容的變化

  • Rxswift代碼
import UIKit
import RxSwift
import RxCocoa
 
class ViewController: UIViewController {
     
    let disposeBag = DisposeBag()
     
    override func viewDidLoad() {
         
        //建立文本輸入框
        let textField = UITextField(frame: CGRect(x:10, y:80, width:200, height:30))
        textField.borderStyle = UITextBorderStyle.roundedRect
        self.view.addSubview(textField)
         
        //當文本框內容改變時,將內容輸出到控制檯上
        textField.rx.text.orEmpty.asObservable()
            .subscribe(onNext: {
                print("您輸入的是:\($0)")
            })
            .disposed(by: disposeBag)

//當文本框內容改變時,將內容輸出到控制檯上
textField.rx.text.orEmpty.changed
    .subscribe(onNext: {
        print("您輸入的是:\($0)")
    })
    .disposed(by: disposeBag)
    
    }
}
複製代碼

實例92:Rxswift將textField的內容綁定到其餘控件上

  • Rxswift代碼
import UIKit
import RxSwift
import RxCocoa
 
class ViewController: UIViewController {
     
    let disposeBag = DisposeBag()
     
    override func viewDidLoad() {
         
        //建立文本輸入框
        let inputField = UITextField(frame: CGRect(x:10, y:80, width:200, height:30))
        inputField.borderStyle = UITextBorderStyle.roundedRect
        self.view.addSubview(inputField)
         
        //建立文本輸出框
        let outputField = UITextField(frame: CGRect(x:10, y:150, width:200, height:30))
        outputField.borderStyle = UITextBorderStyle.roundedRect
        self.view.addSubview(outputField)
         
        //建立文本標籤
        let label = UILabel(frame:CGRect(x:20, y:190, width:300, height:30))
        self.view.addSubview(label)
         
        //建立按鈕
        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)
         
         
        //當文本框內容改變
        let input = inputField.rx.text.orEmpty.asDriver() // 將普通序列轉換爲 Driver
            .throttle(0.3) //在主線程中操做,0.3秒內值若屢次改變,取最後一次
         
        //內容綁定到另外一個輸入框中
        input.drive(outputField.rx.text)
            .disposed(by: disposeBag)
         
        //內容綁定到文本標籤中
        input.map{ "當前字數:\($0.count)" }
            .drive(label.rx.text)
            .disposed(by: disposeBag)
         
        //根據內容字數決定按鈕是否可用
        input.map{ $0.count > 5 }
            .drive(button.rx.isEnabled)
            .disposed(by: disposeBag)
    }
}
複製代碼

實例93:Rxswift同時監聽多個 textField 內容的變化

  • 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)
    }
}
複製代碼

實例94:Rxswift實現textField事件監聽 經過 rx.controlEvent 能夠監聽輸入框的各類事件,且多個事件狀態能夠自由組合。除了各類 UI 控件都有的 touch 事件外,輸入框還有以下幾個獨有的事件:

  • editingDidBegin:開始編輯(開始輸入內容)

  • editingChanged:輸入內容發生改變

  • editingDidEnd:結束編輯

  • editingDidEndOnExit:按下 return 鍵結束編輯

  • allEditingEvents:包含前面的全部編輯相關事件

  • Rxswift代碼

textField.rx.controlEvent([.editingDidBegin]) //狀態能夠組合
    .asObservable()
    .subscribe(onNext: { _ in
        print("開始編輯內容!")
    }).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)
    }
}
複製代碼

實例95:Rxswift實現textField事件監聽

  • Rxswift代碼
複製代碼

UITextView

實例100

  • 傳統代碼
複製代碼
  • Rxswift代碼
import UIKit
import RxSwift
import RxCocoa
 
class ViewController: UIViewController {
     
    let disposeBag = DisposeBag()
     
    @IBOutlet weak var textView: UITextView!
     
    override func viewDidLoad() {
         
        //開始編輯響應
        textView.rx.didBeginEditing
            .subscribe(onNext: {
                print("開始編輯")
            })
            .disposed(by: disposeBag)
         
        //結束編輯響應
        textView.rx.didEndEditing
            .subscribe(onNext: {
                print("結束編輯")
            })
            .disposed(by: disposeBag)
         
        //內容發生變化響應
        textView.rx.didChange
            .subscribe(onNext: {
                print("內容發生改變")
            })
            .disposed(by: disposeBag)
         
        //選中部分變化響應
        textView.rx.didChangeSelection
            .subscribe(onNext: {
                print("選中部分發生變化")
            })
            .disposed(by: disposeBag)
    }
}
複製代碼

UITableView

  • 傳統Swift使用UITableView 實例110
//歌曲結構體
struct Music {
    let name: String //歌名
    let singer: String //演唱者
     
    init(name: String, singer: String) {
        self.name = name
        self.singer = singer
    }
}

//歌曲列表數據源
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!
     
    //歌曲列表數據源
    let musicListViewModel = MusicListViewModel()
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        //設置代理
        tableView.dataSource = self
        tableView.delegate = self
    }
}
 
extension ViewController: UITableViewDataSource {
    //返回單元格數量
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return musicListViewModel.data.count
    }
     
    //返回對應的單元格
    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 {
    //單元格點擊
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("你選中的歌曲信息【\(musicListViewModel.data[indexPath.row])】")
    }
}
複製代碼
  • Rxswift 的UITableView

實例111

/*這裏咱們將 data 屬性變成一個可觀察序列對象(Observable Squence), 而對象當中的內容和咱們以前在數組當中所包含的內容是徹底同樣的。 */
//歌曲列表數據源
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!
     
    //歌曲列表數據源
    let musicListViewModel = MusicListViewModel()
     
    //負責對象銷燬
    let disposeBag = DisposeBag()
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        //將數據源數據綁定到tableView上
        musicListViewModel.data
            .bind(to: 
            /* rx.items(cellIdentifier:):這是 Rx 基於 cellForRowAt 數據源方法的一個封裝。 傳統方式中咱們還要有個 numberOfRowsInSection 方法, 使用 Rx 後就再也不須要了(Rx 已經幫咱們完成了相關工做)。 */ 
       tableView.rx.items(cellIdentifier:"musicCell")) { _, music, cell in
                cell.textLabel?.text = music.name
                cell.detailTextLabel?.text = music.singer
            }.disposed(by: disposeBag)
         
        //tableView點擊響應
       /* rx.modelSelected: 這是 Rx 基於 UITableView委託回調方法 didSelectRowAt 的一個封裝。 */ tableView.rx.modelSelected(Music.self).subscribe(onNext: { music in
            print("你選中的歌曲信息【\(music)】")
        }).disposed(by: disposeBag)
        /*DisposeBag:做用是 Rx 在視圖控制器或者其持有者將要銷燬的時候, 自動釋法掉綁定在它上面的資源。 它是經過相似「訂閱處置機制」方式實現(相似於 NotificationCenter 的 removeObserver)。*/
    }
}

複製代碼

UICollectionView

實例120

  • 傳統代碼
複製代碼
  • Rxswift代碼
複製代碼

UIPickerView

實例130

  • 傳統代碼
複製代碼
  • Rxswift代碼
複製代碼

UIDatePicker

實例140

  • 傳統代碼
複製代碼
  • Rxswift代碼
複製代碼

UISlider

實例150

  • 傳統代碼
複製代碼
  • Rxswift代碼
複製代碼

UIStepper

實例160

  • 傳統代碼
複製代碼
  • Rxswift代碼
複製代碼
相關文章
相關標籤/搜索