RxSwift(14)— MVVM雙向綁定

就問此時此刻還有誰?45度仰望天空,該死!我這無處安放的魅力!git


RxSwift 目錄直通車 --- 和諧學習,不急不躁!github


1、首先面向開發咱們看看RxSwift在TableView的應用

/// tableView -- RX
func setupTableViewRX() {
    let dataOB = BehaviorSubject.init(value: self.viewModel.dataArray)
    // 騷起來
// dataOB.bind(to: self.tableView.rx.items){(tabView,row,model) ->LGTableViewCell in
// let cell = tabView.dequeueReusableCell(withIdentifier: resuseID) as! LGTableViewCell
// cell.setUIData(model as! LGModel)
// return cell
// }.disposed(by: disposeBag)
    
    dataOB.asObserver().bind(to: self.tableView.rx.items(cellIdentifier: resuseID, cellType: LGTableViewCell.self)){
        (row,model,cell) in
        cell.setUIData(model as! LGModel)
    }.disposed(by: self.disposeBag)
    
    // tableView點擊事件
    tableView.rx.itemSelected.subscribe(onNext: { [weak self](indexPath) in
        print("點擊\(indexPath)行")
        self?.navigationController?.pushViewController(LGSectionViewController(), animated: true)
        self?.tableView.deselectRow(at: indexPath, animated: true)
    }).disposed(by: self.disposeBag)
    
    // tableView複選點擊事件
    tableView.rx.itemDeselected.subscribe(onNext: { (indexPath) in
        print("再次點擊\(indexPath)行")
    }).disposed(by: self.disposeBag)
    
    // tableView移動事件
    tableView.rx.itemMoved.subscribe(onNext: { [weak self] (sourceIndex,destinationIndex) in
        print("從\(sourceIndex)移動到\(destinationIndex)")
        self?.viewModel.dataArray.swapAt(sourceIndex.row, destinationIndex.row)
        self?.loadUI(obSubject: dataOB)
    }).disposed(by: self.disposeBag)
    
    // tableView刪除事件
    tableView.rx.itemDeleted.subscribe(onNext: { [weak self](indexPath) in
        print("點擊刪除\(indexPath)行")
        self?.viewModel.dataArray.remove(at: indexPath.row)
        self?.loadUI(obSubject: dataOB)
    }).disposed(by: self.disposeBag)
    
    // tableView新增事件
    tableView.rx.itemInserted.subscribe(onNext: { [weak self](indexPath) in
        print("添加數據在\(indexPath)行")
        guard let model = self?.viewModel.dataArray.last else{
            print("數據有問題,沒法新增")
            return
        }
        self?.viewModel.dataArray.insert(model, at: indexPath.row)
        self?.loadUI(obSubject: dataOB)
    }).disposed(by: self.disposeBag)    
}
複製代碼
  • TableView點擊、複選、新增、刪除、移動所有簡潔實現
  • RxSwift一旦趕上了TableView,根本不須要那些噁心的膠水代碼
  • delegate & dataSource的賦值直接免去
  • 膠水代理以及數據源代理的實現(畢竟咱們如今列表界面愈來愈多,膠水的代碼的優化,太爽了)
  • 咱們全部的事件訂閱都在相應地方,咱們更容易管理
  • 函數式回調致使咱們的邏輯代碼與功能代碼綁定在一塊,可讀性更強

2、分組的TableView

/// Rx 處理分組
func setupTableViewRX() {
    let tableViewDataSource = RxTableViewSectionedReloadDataSource<SectionModel<String,LGSectionModel>>(configureCell: { [weak self](dataSource, tab, indexPath, model) -> LGTableViewCell in
        let cell = tab.dequeueReusableCell(withIdentifier: self?.resuseID ?? "resuseID_LGSectionViewController", for: indexPath) as! LGTableViewCell
        cell.setUISectionData(model)
        cell.selectionStyle = .none
        return cell
    },titleForHeaderInSection: { dataSource,index -> String in
        // print("數據:\(dataSource.sectionModels[index].identity)")
        return dataSource.sectionModels[index].model
    })

    /// 咱們上次就是經過bind函數,這裏咱們變化一下
    self.data.githubData.asDriver(onErrorJustReturn: [])
        .drive(self.tableView.rx.items(dataSource: tableViewDataSource))
        .disposed(by: self.disposeBag)
    
    /// 跳轉到網絡相關Demo
    self.tableView.rx.itemSelected.subscribe(onNext: { [weak self](indexPath) in
        self?.navigationController?.pushViewController(LGNetworkViewController(), animated: true)
    }).disposed(by: self.disposeBag)
}
複製代碼
  • RxCocoa封裝的dataSourcer讓咱們爽的沒法自拔
  • dataSource的承擔了整個數據源代理,而且強勢封裝了代理
  • 數據層的響應直接綁定到了UI,讓數據更簡單傳輸
  • 從上面的代碼一眼就能看出,RxSwift讓咱們的開發更直接面向開發,讓開發更容易

MVVM雙向綁定

override func viewDidLoad() {
    super.viewDidLoad()
    self.setupUI()
    // 如今來一個需求:咱們的輸入框搜索 - 請求網絡 - 下面tableView聯動
    // UI <-> model
    self.searchBar.rx.text.orEmpty
        .bind(to: self.viewModel.searchTextOB)
        .disposed(by: disposeBag)
    
   // 數據層綁定UI
    self.viewModel.searchData.drive(self.tableView.rx.items){ (tableView, indexPath, model) -> LGTableViewCell in
        let cell = tableView.dequeueReusableCell(withIdentifier: self.resuseID) as! LGTableViewCell
        cell.nameLabel.text  = model.name
        cell.classLabel.text = model.url
        return cell
    }
    .disposed(by: disposeBag)
    
    // tittle綁定
    self.viewModel.searchData.map { (array) -> String in
        return "搜索到了 \(array.count) 條數據"
    }
    .drive(self.navigationItem.rx.title)
    .disposed(by: disposeBag)
    
    // 滑動減速綁定
    self.tableView.rx.didEndDecelerating
        .subscribe { [weak self] in
            self?.searchBar.endEditing(true)
    }.disposed(by: disposeBag)
}
複製代碼
  • 這裏就是咱們RxSwift世界裏的ViewController,這纔是真正的輕量化的VC,至始至終都只作一件事:創建View與ViewModel之間的綁定依賴關係
  • 經過咱們搜索欄的響應,發送數據給咱們的ViewModel,讓它在它的世界裏處理業務層,網絡層數據的返回
  • 經過ViewModel響應對外,達到數據綁定到UI的效果
  • ViewModel裏面咱們運用RxSwift的高階函數,處理邏輯
lazy var searchData: Driver<[LGReposityModel]> = {
    return self.searchTextOB.asObserver()
        .throttle(RxTimeInterval.milliseconds(300), scheduler: MainScheduler.instance)
        .distinctUntilChanged()
        .flatMapFirst(LGComprehensiveViewModel.resposeData)
        .asDriver(onErrorJustReturn: [])
}()
複製代碼
  • UI事件搜索的響應傳入,經過一個懶加載的數據返回
  • 這個響應的序列經過throttle保證了相隔0.3秒發送一次事件
  • distinctUntilChanged函數保證了帶寬,直到搜索字眼變更的時候才請求
  • flatMapFirst由於序列的序列,咱們下沉請求,回調結果
  • asDriver包裝成Drive序列,保證狀態共享,主線程調度,沒有錯誤返回
static func resposeData(_ githunId: String) -> Observable<[LGReposityModel]> {
    guard !githunId.isEmpty,let url = URL(string: "https://api.github.com/users/\(githunId)/repos") else {
        return Observable.just([])
    }
    
   return URLSession.shared.rx.json(url: url)
            .retry()
            .observeOn(ConcurrentDispatchQueueScheduler(qos: .background))
            .map(LGComprehensiveViewModel.parseData)
}
複製代碼
  • 經過上面的響應,這裏封裝網絡URLSession.shared.rx.json,返回json
  • 爲了保證請求網絡在子線程,這裏調用observeOn
  • 請求回來的數據還不是咱們所想要的,這裏map映射,下沉的序列化結果
static func parseData(_ json: Any) -> [LGReposityModel] {
    guard let items = json as? [[String: Any]] else {return []}
    guard let result = [LGReposityModel].deserialize(from: items) else { return [] }
    return result as! [LGReposityModel]
}
複製代碼
  • 這裏就是普通的判空,而後經過HandJSON進行數據解析
  • 返回的結果序列成模型數組,而後返回響應
  • 響應層層下發,數據層層處理上升
  • 根據外界的關係,完美實現雙向綁定

完美實現聯動,MVVM雙向綁定加入RxSwift的身影也就更出色json

  • 當北京趕上西雅圖
  • 當愛情趕上婚姻
  • 當興趣趕上事業
  • 當MVVM趕上RxSwift
  • 個人天一切的一切都是那麼的美好,安逸~~~舒服!!!

全部的努力都會在某一個時刻兌現,咱們不少小夥伴都會感嘆怎麼還不來!你要知道:毋庸置疑,好的事情總會到來,當他來晚的時候也不失爲一種驚喜swift

就問此時此刻還有誰?45度仰望天空,該死!我這無處安放的魅力!api

相關文章
相關標籤/搜索