2017-09-29 4 views
0

J'ai un projet très simple, où je veux filtrer dynamiquement le contenu dans UITableView concernant l'index pressé dans UISegmentedControl. J'utilise MVVM avec RxSwift, Realm et RxDataSources. Donc, mon problème, que si je veux mettre à jour le contenu dans UITableView je dois créer «spécial» DisposeBag, uniquement à cette fin, et sur chaque sélection UISegmentedControl zéro et créer à nouveau. Seulement dans ce cas, si je comprends bien, l'abonnement est renouvelé, et UITableView affiche de nouveaux résultats de Realm. Alors, y a-t-il une meilleure façon de faire une telle opération? Sans m'abonner à chaque fois, lorsque je change d'onglet dans UISegmentedControl. Voici mon code:Filtrer dynamiquement les résultats avec RxSwift et Realm

//ViewController 
class MyViewController : UIViewController { 

    //MARK: - Props 
    @IBOutlet weak var tableView: UITableView! 
    @IBOutlet weak var segmentedControl: UISegmentedControl! 

    let dataSource = RxTableViewSectionedReloadDataSource<ItemsSection>() 
    let disposeBag = DisposeBag() 

    var tableViewBag: DisposeBag! 
    var viewModel: MyViewModel = MyViewModel() 

    //MARK: - View lifecycle 
    override func viewDidLoad() { 
    super.viewDidLoad() 
    self.setupRxTableView() 
    } 

    //MARK: - Setup observables 
    fileprivate func setupRxTableView() { 
    dataSource.configureCell = { ds, tv, ip, item in 
     let cell = tv.dequeueReusableCell(withIdentifier: "ItemCell") as! ItemTableViewCell 
     return cell 
    } 

    bindDataSource() 

    segmentedControl.rx.value.asDriver() 
     .drive(onNext: {[weak self] index in 
     guard let sSelf = self else { return } 
     switch index { 
     case 1: 
      sSelf.bindDataSource(filter: .active) 
     case 2: 
      sSelf.bindDataSource(filter: .groups) 
     default: 
      sSelf.bindDataSource() 
     } 
     }).disposed(by: disposeBag) 
    } 

    private func bindDataSource(filter: Filter = .all) { 
    tableViewBag = nil 
    tableViewBag = DisposeBag() 
    viewModel.populateApplying(filter: filter) 
     }).bind(to: self.tableView.rx.items(dataSource: dataSource)) 
     .disposed(by: tableViewBag) 
    } 
} 

//ViewModel 
    class MyViewModel { 
     func populateApplying(filter: Filter) -> Observable<[ItemsSection]> { 
     return Observable.create { [weak self] observable -> Disposable in 
     guard let sSelf = self else { return Disposables.create() } 
     let realm = try! Realm() 
     var items = realm.objects(Item.self).sorted(byKeyPath: "date", ascending: false) 
     if let predicate = filter.makePredicate() { items = items.filter(predicate) } 
     let section = [ItemsSection(model: "", items: Array(items))] 
     observable.onNext(section) 

     sSelf.itemsToken = items.addNotificationBlock { changes in 
      switch changes { 
      case .update(_, _, _, _): 
      let section = [ItemsSection(model: "", items: Array(items))] 
      observable.onNext(section) 
      default: break 
      } 
     } 
     return Disposables.create() 
     } 
    } 
    } 

Répondre

0

Ne se souvient pas si cela se brise MVVM du haut de ma tête, mais je variable pas ce que vous cherchez?

Variable<[TableData]> data = new Variable<[TableData]>([]) 

func applyFilter(filter: Predicate){ 
    data.value = items.filter(predicate) //Any change to to the value will cause the table to reload 
} 

et quelque part dans le viewController

viewModel.data.rx.asDriver().drive 
     (tableView.rx.items(cellIdentifier: "ItemCell", cellType: ItemTableViewCell.self)) 
{ row, data, cell in 

    //initialize cells with data 
}