Just ask who else is there right now? 45 degrees up in the sky, damn it! My charm with no place to put it!

  • RxSwift (1) — Preliminary study
  • RxSwift (2) – Core logic source code analysis
  • RxSwift (3) – How the Observable sequence is created
  • RxSwift (4) — Higher Order functions (1)
  • RxSwift (5) — Higher Order functions (lower)
  • RxSwift (6) — Scheduler source scheduler
  • RxSwift (7) — Scheduler scheduler
  • RxSwift (8) — KVO Low-level Exploration (1)
  • RxSwift (9) — KVO Low-level Exploration (2)
  • RxSwift (10) — Summary of scene sequences
  • RxSwift (11) — Dispose source code parsing
  • RxSwift (12) — Subject is both offensive and defensive
  • RxSwift (13) — Climb over the pit
  • RxSwift (14) — MVVM bidirectional binding

RxSwift directory through train — Harmonious learning, not impatient!


First, we look at RxSwift in TableView application

/// tableView -- RX
func setupTableViewRX(a) {
    let dataOB = BehaviorSubject.init(value: self.viewModel.dataArray)
    / / SAO
// 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 click event
    tableView.rx.itemSelected.subscribe(onNext: { [weak self](indexPath) in
        print(Click on the"\(indexPath)Line")
        self? .navigationController? .pushViewController(LGSectionViewController(), animated: true)
        self? .tableView.deselectRow(at: indexPath, animated:true)
    }).disposed(by: self.disposeBag)
    
    // tableView check click events
    tableView.rx.itemDeselected.subscribe(onNext: { (indexPath) in
        print("Click again\(indexPath)Line")
    }).disposed(by: self.disposeBag)
    
    // tableView move event
    tableView.rx.itemMoved.subscribe(onNext: { [weak self] (sourceIndex,destinationIndex) in
        print("From the\(sourceIndex)Move to the\(destinationIndex)")
        self? .viewModel.dataArray.swapAt(sourceIndex.row, destinationIndex.row)self? .loadUI(obSubject: dataOB) }).disposed(by:self.disposeBag)
    
    // tableView deletes the event
    tableView.rx.itemDeleted.subscribe(onNext: { [weak self](indexPath) in
        print("Click Delete\(indexPath)Line")
        self? .viewModel.dataArray.remove(at: indexPath.row)self? .loadUI(obSubject: dataOB) }).disposed(by:self.disposeBag)
    
    // Add event to tableView
    tableView.rx.itemInserted.subscribe(onNext: { [weak self](indexPath) in
        print("Add data in\(indexPath)Line")
        guard let model = self? .viewModel.dataArray.lastelse{
            print("There is something wrong with the data. It cannot be added.")
            return
        }
        self? .viewModel.dataArray.insert(model, at: indexPath.row)self? .loadUI(obSubject: dataOB) }).disposed(by:self.disposeBag)    
}
Copy the code
  • TableViewtheClick, check, Add, Delete, MoveAll concise implementation
  • RxSwiftOnce you meetTableViewYou don’t need that disgusting glue code
  • delegate & dataSourceThe assignment of
  • Glue agent and data source agent implementation (after all, we are now more and more list interface, glue code optimization, too cool)
  • All of our event subscriptions are in place and we are easier to manage
  • Functional callbacks cause our logical code to be tied together with our functional code, making it more readable

Group TableView

/// Rx processing group
func setupTableViewRX(a) {
    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(" data :\(dataSource. SectionModels [index].identity)")
        return dataSource.sectionModels[index].model
    })

    /// We used bind last time
    self.data.githubData.asDriver(onErrorJustReturn: [])
        .drive(self.tableView.rx.items(dataSource: tableViewDataSource))
        .disposed(by: self.disposeBag)
    
    /// Jump to network-related Demo
    self.tableView.rx.itemSelected.subscribe(onNext: { [weak self](indexPath) in
        self? .navigationController? .pushViewController(LGNetworkViewController(), animated: true)
    }).disposed(by: self.disposeBag)
}
Copy the code
  • RxCocoaencapsulateddataSourcerIt makes us feel so good
  • dataSourceTakes over the entire data source agent and forcefully encapsulates the agent
  • The data layer’s responses are directly bound to the UI, making it easier to transfer data
  • As you can see at a glance from the code above,RxSwiftMake our development more direct to development, make development easier

MVVM bidirectional binding

override func viewDidLoad(a) {
    super.viewDidLoad()
    self.setupUI()
    // Now come a requirement: our input box search - request network - below tableView linkage
    // UI <-> model
    self.searchBar.rx.text.orEmpty
        .bind(to: self.viewModel.searchTextOB)
        .disposed(by: disposeBag)
    
   // Data layer binding 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 binding
    self.viewModel.searchData.map { (array) -> String in
        return "The search was found.\(array.count)The data"
    }
    .drive(self.navigationItem.rx.title)
    .disposed(by: disposeBag)
    
    // Slide-down binding
    self.tableView.rx.didEndDecelerating
        .subscribe { [weak self] in
            self? .searchBar.endEditing(true)
    }.disposed(by: disposeBag)
}
Copy the code
  • And here we areRxSwiftIn the worldViewControllerThis is the real thingLightweight VCDo one thing at a time:Establish binding dependencies between views and ViewModels
  • Send data to us via our search bar responseViewModelLet it handle the return of business layer, network layer data in its world
  • throughViewModelResponds externally, reaching data binding toUIThe effect of
  • inViewModelWhere we useRxSwiftHigh order function, processing logic
lazy var searchData: Driver"[LGReposityModel] > = {return self.searchTextOB.asObserver()
        .throttle(RxTimeInterval.milliseconds(300), scheduler: MainScheduler.instance)
        .distinctUntilChanged()
        .flatMapFirst(LGComprehensiveViewModel.resposeData)
        .asDriver(onErrorJustReturn: [])
}()
Copy the code
  • The UI event search response comes in and is returned with a lazily loaded data
  • The sequence of responses goes throughthrottleEvents are guaranteed to be sent at an interval of 0.3 seconds
  • distinctUntilChangedThe function guarantees bandwidth until the search term changes
  • flatMapFirstBecause of the sequence of sequences, we sink the request, callback the result
  • asDriverPackaged inDriveSequence, guaranteed state sharing, main thread scheduling, no error return
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)
}
Copy the code
  • With the response above, the network is encapsulated hereURLSession.shared.rx.jsonTo return tojson
  • To ensure that the requesting network is in the child thread, call hereobserveOn
  • The requested data back is not what we want, heremapThe mapping,Sinking serialization results
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]}Copy the code
  • It’s just a normal call and passHandJSONPerform data parsing
  • The result sequence is returned as an array of models, and the response is returned
  • Response layer by layer, data processing layer up
  • According to the external relationship, perfect realization of two-way binding

Perfect linkage, MVVM bidirectional binding to join RxSwift figure is also more outstanding

  • When Beijing meets Seattle
  • When love meets marriage
  • When interest meets career
  • When MVVM meets RxSwift
  • My god everything is so beautiful, comfortable ~~~ comfortable!!

All efforts will be realized at a certain point, many of our partners will sigh why not! You know, good things come, of course, and it was a surprise when he was late

Just ask who else is there right now? 45 degrees up in the sky, damn it! My charm with no place to put it!